Compare commits

..

25 Commits

Author SHA1 Message Date
Liam
d00b7be2d6 core/debugger: fix crash due to incorrect lambda capture 2022-06-06 23:39:48 -04:00
bunnei
708e5b027f Merge pull request #8367 from Docteh/say_win11
Logging: Report Post Windows 10 2004 versions, like Windows 11
2022-06-05 18:44:48 -07:00
bunnei
c33c9c76bf Merge pull request #8426 from liamwhite/elf
common: consolidate ELF structure definitions
2022-06-05 16:52:06 -07:00
Mai M
cad53179ed Merge pull request #8419 from liamwhite/library-list
gdbstub: add missing library list query
2022-06-05 18:23:29 -04:00
Liam
3c313a43fd common: consolidate ELF structure definitions 2022-06-05 09:42:05 -04:00
bunnei
45bdbf538c Merge pull request #8395 from german77/ir_stub
service: hid: Improve stub of IRS
2022-06-04 01:26:08 -07:00
Liam
2f2e443858 gdbstub: add missing library list command 2022-06-03 20:42:13 -04:00
Fernando S
14db101148 Merge pull request #8414 from bylaws/master
Maxwell3D: Fix 3D semaphore counter type 0 handling
2022-06-03 18:02:10 +02:00
Billy Laws
ea89cf8639 Maxwell3D: Fix 3D semaphore counter type 0 handling
Counter type 0 actually releases the semaphore payload rather than a constant zero as was previously thought. This is required by Skyrim.
2022-06-02 21:46:38 +01:00
Mai M
5c0a31e29f Merge pull request #8410 from liamwhite/thread-names
gdbstub: Support reading guest thread names
2022-06-02 16:34:41 -04:00
Liam
07922abffc core/debugger: Support reading guest thread names 2022-06-01 21:25:32 -04:00
Mai M
114a4562ed Merge pull request #8409 from liamwhite/tdesc-fix
gdbstub: fix target descriptions
2022-06-01 21:16:33 -04:00
Morph
858f8ac6d9 Merge pull request #8402 from liamwhite/better-step
core/debugger: Improved stepping mechanism and misc fixes
2022-06-01 20:46:10 -04:00
Liam
b71130e6f1 gdbstub: fix target descriptions 2022-06-01 20:31:24 -04:00
bunnei
af418eb666 Merge pull request #8400 from Docteh/fullscreen_glitch
fix UI opening fullscreen after certain crashes
2022-06-01 10:26:24 -07:00
liamwhite
a2f6a2480d Merge pull request #8404 from Morph1984/virtual
core/debugger: Define defaulted virtual destructors
2022-06-01 12:30:47 -04:00
liamwhite
503feba7e4 Merge pull request #8403 from Morph1984/cast
gdbstub: Explicitly cast return type to u8
2022-06-01 12:30:32 -04:00
Morph
69511aed3d core/debugger: Define defaulted virtual destructors
Resolves an MSVC warning where a virtual destructor is not defined in the base class with virtual functions.
2022-06-01 02:28:34 -04:00
Morph
a32f6e9d8e gdbstub: Explicitly cast return type to u8
Otherwise, the addition promotes the returned value to an int instead of keeping it as a u8.
2022-06-01 01:40:18 -04:00
Kyle Kienapfel
36df3ce97e fix UI opening fullscreen after certain crashes
Sometimes when yuzu crashes, it restarts with the games list in fullscreen,
which would be fine, except there isn't an easy way to exit this.
It also doesn't occur often enough for qt-config.ini files to be in good supply.

UILayout\geometry value in qt-config.ini is the culprit,
 at least for the one provided.

Proposed fix is to simply check isFullScreen when yuzu is starting up,
and take it out of full screen immediately
2022-05-31 21:24:31 -07:00
Mai M
de2f2e5140 Merge pull request #8394 from liamwhite/debugger
core/debugger: Implement new GDB stub debugger
2022-06-01 00:19:49 -04:00
Mai M
72b34650f9 Merge pull request #8401 from zhaobot/tx-update-20220601034505
Update translations (2022-06-01)
2022-05-31 23:53:39 -04:00
The yuzu Community
105c60b984 Update translations (2022-06-01) 2022-06-01 03:45:35 +00:00
Narr the Reg
e609bc1c6a service: hid: Improve stub of IRS 2022-05-31 10:26:13 -05:00
Kyle K
017a18f42e Logging: Report Post Windows 10 2004 versions, like Windows 11
Qt5 and Qt6 don't really do a good job of reporting Windows versions past the 2004 version.

Current: Windows 10 Version 2009
This Patch: Windows 10 Version 21H1 (Build 19043.1706)
Also: Windows 11 Version 21H2 (Build 22000.675)

Fixes: #8362
2022-05-28 20:48:19 -07:00
41 changed files with 5917 additions and 5198 deletions

395
dist/languages/ca.ts vendored

File diff suppressed because it is too large Load Diff

395
dist/languages/cs.ts vendored

File diff suppressed because it is too large Load Diff

395
dist/languages/da.ts vendored

File diff suppressed because it is too large Load Diff

395
dist/languages/de.ts vendored

File diff suppressed because it is too large Load Diff

395
dist/languages/el.ts vendored

File diff suppressed because it is too large Load Diff

416
dist/languages/es.ts vendored

File diff suppressed because it is too large Load Diff

525
dist/languages/fr.ts vendored

File diff suppressed because it is too large Load Diff

395
dist/languages/id.ts vendored

File diff suppressed because it is too large Load Diff

413
dist/languages/it.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

395
dist/languages/nb.ts vendored

File diff suppressed because it is too large Load Diff

401
dist/languages/nl.ts vendored

File diff suppressed because it is too large Load Diff

395
dist/languages/pl.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

395
dist/languages/sv.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

395
dist/languages/vi.ts vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -58,6 +58,7 @@ add_library(common STATIC
div_ceil.h
dynamic_library.cpp
dynamic_library.h
elf.h
error.cpp
error.h
expected.h

333
src/common/elf.h Normal file
View File

@@ -0,0 +1,333 @@
// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <cstddef>
#include "common_types.h"
namespace Common {
namespace ELF {
/* Type for a 16-bit quantity. */
using Elf32_Half = u16;
using Elf64_Half = u16;
/* Types for signed and unsigned 32-bit quantities. */
using Elf32_Word = u32;
using Elf32_Sword = s32;
using Elf64_Word = u32;
using Elf64_Sword = s32;
/* Types for signed and unsigned 64-bit quantities. */
using Elf32_Xword = u64;
using Elf32_Sxword = s64;
using Elf64_Xword = u64;
using Elf64_Sxword = s64;
/* Type of addresses. */
using Elf32_Addr = u32;
using Elf64_Addr = u64;
/* Type of file offsets. */
using Elf32_Off = u32;
using Elf64_Off = u64;
/* Type for section indices, which are 16-bit quantities. */
using Elf32_Section = u16;
using Elf64_Section = u16;
/* Type for version symbol information. */
using Elf32_Versym = Elf32_Half;
using Elf64_Versym = Elf64_Half;
constexpr size_t ElfIdentSize = 16;
/* The ELF file header. This appears at the start of every ELF file. */
struct Elf32_Ehdr {
std::array<u8, ElfIdentSize> e_ident; /* Magic number and other info */
Elf32_Half e_type; /* Object file type */
Elf32_Half e_machine; /* Architecture */
Elf32_Word e_version; /* Object file version */
Elf32_Addr e_entry; /* Entry point virtual address */
Elf32_Off e_phoff; /* Program header table file offset */
Elf32_Off e_shoff; /* Section header table file offset */
Elf32_Word e_flags; /* Processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size in bytes */
Elf32_Half e_phentsize; /* Program header table entry size */
Elf32_Half e_phnum; /* Program header table entry count */
Elf32_Half e_shentsize; /* Section header table entry size */
Elf32_Half e_shnum; /* Section header table entry count */
Elf32_Half e_shstrndx; /* Section header string table index */
};
struct Elf64_Ehdr {
std::array<u8, ElfIdentSize> e_ident; /* Magic number and other info */
Elf64_Half e_type; /* Object file type */
Elf64_Half e_machine; /* Architecture */
Elf64_Word e_version; /* Object file version */
Elf64_Addr e_entry; /* Entry point virtual address */
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */
Elf64_Word e_flags; /* Processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size in bytes */
Elf64_Half e_phentsize; /* Program header table entry size */
Elf64_Half e_phnum; /* Program header table entry count */
Elf64_Half e_shentsize; /* Section header table entry size */
Elf64_Half e_shnum; /* Section header table entry count */
Elf64_Half e_shstrndx; /* Section header string table index */
};
constexpr u8 ElfClass32 = 1; /* 32-bit objects */
constexpr u8 ElfClass64 = 2; /* 64-bit objects */
constexpr u8 ElfData2Lsb = 1; /* 2's complement, little endian */
constexpr u8 ElfVersionCurrent = 1; /* EV_CURRENT */
constexpr u8 ElfOsAbiNone = 0; /* System V ABI */
constexpr u16 ElfTypeNone = 0; /* No file type */
constexpr u16 ElfTypeRel = 0; /* Relocatable file */
constexpr u16 ElfTypeExec = 0; /* Executable file */
constexpr u16 ElfTypeDyn = 0; /* Shared object file */
constexpr u16 ElfMachineArm = 40; /* ARM */
constexpr u16 ElfMachineAArch64 = 183; /* ARM AARCH64 */
constexpr std::array<u8, ElfIdentSize> Elf32Ident{
0x7f, 'E', 'L', 'F', ElfClass32, ElfData2Lsb, ElfVersionCurrent, ElfOsAbiNone};
constexpr std::array<u8, ElfIdentSize> Elf64Ident{
0x7f, 'E', 'L', 'F', ElfClass64, ElfData2Lsb, ElfVersionCurrent, ElfOsAbiNone};
/* Section header. */
struct Elf32_Shdr {
Elf32_Word sh_name; /* Section name (string tbl index) */
Elf32_Word sh_type; /* Section type */
Elf32_Word sh_flags; /* Section flags */
Elf32_Addr sh_addr; /* Section virtual addr at execution */
Elf32_Off sh_offset; /* Section file offset */
Elf32_Word sh_size; /* Section size in bytes */
Elf32_Word sh_link; /* Link to another section */
Elf32_Word sh_info; /* Additional section information */
Elf32_Word sh_addralign; /* Section alignment */
Elf32_Word sh_entsize; /* Entry size if section holds table */
};
struct Elf64_Shdr {
Elf64_Word sh_name; /* Section name (string tbl index) */
Elf64_Word sh_type; /* Section type */
Elf64_Xword sh_flags; /* Section flags */
Elf64_Addr sh_addr; /* Section virtual addr at execution */
Elf64_Off sh_offset; /* Section file offset */
Elf64_Xword sh_size; /* Section size in bytes */
Elf64_Word sh_link; /* Link to another section */
Elf64_Word sh_info; /* Additional section information */
Elf64_Xword sh_addralign; /* Section alignment */
Elf64_Xword sh_entsize; /* Entry size if section holds table */
};
constexpr u32 ElfShnUndef = 0; /* Undefined section */
constexpr u32 ElfShtNull = 0; /* Section header table entry unused */
constexpr u32 ElfShtProgBits = 1; /* Program data */
constexpr u32 ElfShtSymtab = 2; /* Symbol table */
constexpr u32 ElfShtStrtab = 3; /* String table */
constexpr u32 ElfShtRela = 4; /* Relocation entries with addends */
constexpr u32 ElfShtDynamic = 6; /* Dynamic linking information */
constexpr u32 ElfShtNobits = 7; /* Program space with no data (bss) */
constexpr u32 ElfShtRel = 9; /* Relocation entries, no addends */
constexpr u32 ElfShtDynsym = 11; /* Dynamic linker symbol table */
/* Symbol table entry. */
struct Elf32_Sym {
Elf32_Word st_name; /* Symbol name (string tbl index) */
Elf32_Addr st_value; /* Symbol value */
Elf32_Word st_size; /* Symbol size */
u8 st_info; /* Symbol type and binding */
u8 st_other; /* Symbol visibility */
Elf32_Section st_shndx; /* Section index */
};
struct Elf64_Sym {
Elf64_Word st_name; /* Symbol name (string tbl index) */
u8 st_info; /* Symbol type and binding */
u8 st_other; /* Symbol visibility */
Elf64_Section st_shndx; /* Section index */
Elf64_Addr st_value; /* Symbol value */
Elf64_Xword st_size; /* Symbol size */
};
/* How to extract and insert information held in the st_info field. */
static inline u8 ElfStBind(u8 st_info) {
return st_info >> 4;
}
static inline u8 ElfStType(u8 st_info) {
return st_info & 0xf;
}
static inline u8 ElfStInfo(u8 st_bind, u8 st_type) {
return static_cast<u8>((st_bind << 4) + (st_type & 0xf));
}
constexpr u8 ElfBindLocal = 0; /* Local symbol */
constexpr u8 ElfBindGlobal = 1; /* Global symbol */
constexpr u8 ElfBindWeak = 2; /* Weak symbol */
constexpr u8 ElfTypeUnspec = 0; /* Symbol type is unspecified */
constexpr u8 ElfTypeObject = 1; /* Symbol is a data object */
constexpr u8 ElfTypeFunc = 2; /* Symbol is a code object */
static inline u8 ElfStVisibility(u8 st_other) {
return static_cast<u8>(st_other & 0x3);
}
constexpr u8 ElfVisibilityDefault = 0; /* Default symbol visibility rules */
constexpr u8 ElfVisibilityInternal = 1; /* Processor specific hidden class */
constexpr u8 ElfVisibilityHidden = 2; /* Sym unavailable in other modules */
constexpr u8 ElfVisibilityProtected = 3; /* Not preemptible, not exported */
/* Relocation table entry without addend (in section of type ShtRel). */
struct Elf32_Rel {
Elf32_Addr r_offset; /* Address */
Elf32_Word r_info; /* Relocation type and symbol index */
};
/* Relocation table entry with addend (in section of type ShtRela). */
struct Elf32_Rela {
Elf32_Addr r_offset; /* Address */
Elf32_Word r_info; /* Relocation type and symbol index */
Elf32_Sword r_addend; /* Addend */
};
struct Elf64_Rela {
Elf64_Addr r_offset; /* Address */
Elf64_Xword r_info; /* Relocation type and symbol index */
Elf64_Sxword r_addend; /* Addend */
};
/* How to extract and insert information held in the r_info field. */
static inline u32 Elf32RelSymIndex(Elf32_Word r_info) {
return r_info >> 8;
}
static inline u8 Elf32RelType(Elf32_Word r_info) {
return static_cast<u8>(r_info & 0xff);
}
static inline Elf32_Word Elf32RelInfo(u32 sym_index, u8 type) {
return (sym_index << 8) + type;
}
static inline u32 Elf64RelSymIndex(Elf64_Xword r_info) {
return static_cast<u32>(r_info >> 32);
}
static inline u32 Elf64RelType(Elf64_Xword r_info) {
return r_info & 0xffffffff;
}
static inline Elf64_Xword Elf64RelInfo(u32 sym_index, u32 type) {
return (static_cast<Elf64_Xword>(sym_index) << 32) + type;
}
constexpr u32 ElfArmCopy = 20; /* Copy symbol at runtime */
constexpr u32 ElfArmGlobDat = 21; /* Create GOT entry */
constexpr u32 ElfArmJumpSlot = 22; /* Create PLT entry */
constexpr u32 ElfArmRelative = 23; /* Adjust by program base */
constexpr u32 ElfAArch64Copy = 1024; /* Copy symbol at runtime */
constexpr u32 ElfAArch64GlobDat = 1025; /* Create GOT entry */
constexpr u32 ElfAArch64JumpSlot = 1026; /* Create PLT entry */
constexpr u32 ElfAArch64Relative = 1027; /* Adjust by program base */
/* Program segment header. */
struct Elf32_Phdr {
Elf32_Word p_type; /* Segment type */
Elf32_Off p_offset; /* Segment file offset */
Elf32_Addr p_vaddr; /* Segment virtual address */
Elf32_Addr p_paddr; /* Segment physical address */
Elf32_Word p_filesz; /* Segment size in file */
Elf32_Word p_memsz; /* Segment size in memory */
Elf32_Word p_flags; /* Segment flags */
Elf32_Word p_align; /* Segment alignment */
};
struct Elf64_Phdr {
Elf64_Word p_type; /* Segment type */
Elf64_Word p_flags; /* Segment flags */
Elf64_Off p_offset; /* Segment file offset */
Elf64_Addr p_vaddr; /* Segment virtual address */
Elf64_Addr p_paddr; /* Segment physical address */
Elf64_Xword p_filesz; /* Segment size in file */
Elf64_Xword p_memsz; /* Segment size in memory */
Elf64_Xword p_align; /* Segment alignment */
};
/* Legal values for p_type (segment type). */
constexpr u32 ElfPtNull = 0; /* Program header table entry unused */
constexpr u32 ElfPtLoad = 1; /* Loadable program segment */
constexpr u32 ElfPtDynamic = 2; /* Dynamic linking information */
constexpr u32 ElfPtInterp = 3; /* Program interpreter */
constexpr u32 ElfPtNote = 4; /* Auxiliary information */
constexpr u32 ElfPtPhdr = 6; /* Entry for header table itself */
constexpr u32 ElfPtTls = 7; /* Thread-local storage segment */
/* Legal values for p_flags (segment flags). */
constexpr u32 ElfPfExec = 0; /* Segment is executable */
constexpr u32 ElfPfWrite = 1; /* Segment is writable */
constexpr u32 ElfPfRead = 2; /* Segment is readable */
/* Dynamic section entry. */
struct Elf32_Dyn {
Elf32_Sword d_tag; /* Dynamic entry type */
union {
Elf32_Word d_val; /* Integer value */
Elf32_Addr d_ptr; /* Address value */
} d_un;
};
struct Elf64_Dyn {
Elf64_Sxword d_tag; /* Dynamic entry type */
union {
Elf64_Xword d_val; /* Integer value */
Elf64_Addr d_ptr; /* Address value */
} d_un;
};
/* Legal values for d_tag (dynamic entry type). */
constexpr u32 ElfDtNull = 0; /* Marks end of dynamic section */
constexpr u32 ElfDtNeeded = 1; /* Name of needed library */
constexpr u32 ElfDtPltRelSz = 2; /* Size in bytes of PLT relocs */
constexpr u32 ElfDtPltGot = 3; /* Processor defined value */
constexpr u32 ElfDtHash = 4; /* Address of symbol hash table */
constexpr u32 ElfDtStrtab = 5; /* Address of string table */
constexpr u32 ElfDtSymtab = 6; /* Address of symbol table */
constexpr u32 ElfDtRela = 7; /* Address of Rela relocs */
constexpr u32 ElfDtRelasz = 8; /* Total size of Rela relocs */
constexpr u32 ElfDtRelaent = 9; /* Size of one Rela reloc */
constexpr u32 ElfDtStrsz = 10; /* Size of string table */
constexpr u32 ElfDtSyment = 11; /* Size of one symbol table entry */
constexpr u32 ElfDtInit = 12; /* Address of init function */
constexpr u32 ElfDtFini = 13; /* Address of termination function */
constexpr u32 ElfDtRel = 17; /* Address of Rel relocs */
constexpr u32 ElfDtRelsz = 18; /* Total size of Rel relocs */
constexpr u32 ElfDtRelent = 19; /* Size of one Rel reloc */
constexpr u32 ElfDtPltRel = 20; /* Type of reloc in PLT */
constexpr u32 ElfDtTextRel = 22; /* Reloc might modify .text */
constexpr u32 ElfDtJmpRel = 23; /* Address of PLT relocs */
constexpr u32 ElfDtBindNow = 24; /* Process relocations of object */
constexpr u32 ElfDtInitArray = 25; /* Array with addresses of init fct */
constexpr u32 ElfDtFiniArray = 26; /* Array with addresses of fini fct */
constexpr u32 ElfDtInitArraySz = 27; /* Size in bytes of DT_INIT_ARRAY */
constexpr u32 ElfDtFiniArraySz = 28; /* Size in bytes of DT_FINI_ARRAY */
constexpr u32 ElfDtSymtabShndx = 34; /* Address of SYMTAB_SHNDX section */
} // namespace ELF
} // namespace Common

View File

@@ -3,73 +3,14 @@
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/elf.h"
#include "core/arm/symbols.h"
#include "core/core.h"
#include "core/memory.h"
using namespace Common::ELF;
namespace Core {
namespace {
constexpr u64 ELF_DYNAMIC_TAG_NULL = 0;
constexpr u64 ELF_DYNAMIC_TAG_STRTAB = 5;
constexpr u64 ELF_DYNAMIC_TAG_SYMTAB = 6;
constexpr u64 ELF_DYNAMIC_TAG_SYMENT = 11;
enum class ELFSymbolType : u8 {
None = 0,
Object = 1,
Function = 2,
Section = 3,
File = 4,
Common = 5,
TLS = 6,
};
enum class ELFSymbolBinding : u8 {
Local = 0,
Global = 1,
Weak = 2,
};
enum class ELFSymbolVisibility : u8 {
Default = 0,
Internal = 1,
Hidden = 2,
Protected = 3,
};
struct ELF64Symbol {
u32 name_index;
union {
u8 info;
BitField<0, 4, ELFSymbolType> type;
BitField<4, 4, ELFSymbolBinding> binding;
};
ELFSymbolVisibility visibility;
u16 sh_index;
u64 value;
u64 size;
};
static_assert(sizeof(ELF64Symbol) == 0x18, "ELF64Symbol has incorrect size.");
struct ELF32Symbol {
u32 name_index;
u32 value;
u32 size;
union {
u8 info;
BitField<0, 4, ELFSymbolType> type;
BitField<4, 4, ELFSymbolBinding> binding;
};
ELFSymbolVisibility visibility;
u16 sh_index;
};
static_assert(sizeof(ELF32Symbol) == 0x10, "ELF32Symbol has incorrect size.");
} // Anonymous namespace
namespace Symbols {
template <typename Word, typename ELFSymbol, typename ByteReader>
@@ -110,15 +51,15 @@ static Symbols GetSymbols(ByteReader ReadBytes) {
const Word value = ReadWord(dynamic_index + sizeof(Word));
dynamic_index += 2 * sizeof(Word);
if (tag == ELF_DYNAMIC_TAG_NULL) {
if (tag == ElfDtNull) {
break;
}
if (tag == ELF_DYNAMIC_TAG_STRTAB) {
if (tag == ElfDtStrtab) {
string_table_offset = value;
} else if (tag == ELF_DYNAMIC_TAG_SYMTAB) {
} else if (tag == ElfDtSymtab) {
symbol_table_offset = value;
} else if (tag == ELF_DYNAMIC_TAG_SYMENT) {
} else if (tag == ElfDtSyment) {
symbol_entry_size = value;
}
}
@@ -134,14 +75,14 @@ static Symbols GetSymbols(ByteReader ReadBytes) {
ELFSymbol symbol{};
ReadBytes(&symbol, symbol_index, sizeof(ELFSymbol));
VAddr string_offset = string_table_offset + symbol.name_index;
VAddr string_offset = string_table_offset + symbol.st_name;
std::string name;
for (u8 c = Read8(string_offset); c != 0; c = Read8(++string_offset)) {
name += static_cast<char>(c);
}
symbol_index += symbol_entry_size;
out[name] = std::make_pair(symbol.value, symbol.size);
out[name] = std::make_pair(symbol.st_value, symbol.st_size);
}
return out;
@@ -152,9 +93,9 @@ Symbols GetSymbols(VAddr base, Core::Memory::Memory& memory, bool is_64) {
[&](void* ptr, size_t offset, size_t size) { memory.ReadBlock(base + offset, ptr, size); }};
if (is_64) {
return GetSymbols<u64, ELF64Symbol>(ReadBytes);
return GetSymbols<u64, Elf64_Sym>(ReadBytes);
} else {
return GetSymbols<u32, ELF32Symbol>(ReadBytes);
return GetSymbols<u32, Elf32_Sym>(ReadBytes);
}
}
@@ -164,9 +105,9 @@ Symbols GetSymbols(std::span<const u8> data, bool is_64) {
}};
if (is_64) {
return GetSymbols<u64, ELF64Symbol>(ReadBytes);
return GetSymbols<u64, Elf64_Sym>(ReadBytes);
} else {
return GetSymbols<u32, ELF32Symbol>(ReadBytes);
return GetSymbols<u32, Elf32_Sym>(ReadBytes);
}
}

View File

@@ -20,15 +20,16 @@ template <typename Readable, typename Buffer, typename Callback>
static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) {
static_assert(std::is_trivial_v<Buffer>);
auto boost_buffer{boost::asio::buffer(&buffer, sizeof(Buffer))};
r.async_read_some(boost_buffer, [&](const boost::system::error_code& error, size_t bytes_read) {
if (!error.failed()) {
const u8* buffer_start = reinterpret_cast<const u8*>(&buffer);
std::span<const u8> received_data{buffer_start, buffer_start + bytes_read};
c(received_data);
}
r.async_read_some(
boost_buffer, [&, c](const boost::system::error_code& error, size_t bytes_read) {
if (!error.failed()) {
const u8* buffer_start = reinterpret_cast<const u8*>(&buffer);
std::span<const u8> received_data{buffer_start, buffer_start + bytes_read};
c(received_data);
}
AsyncReceiveInto(r, buffer, c);
});
AsyncReceiveInto(r, buffer, c);
});
}
template <typename Readable, typename Buffer>
@@ -51,7 +52,7 @@ public:
InitializeServer(port);
}
~DebuggerImpl() {
~DebuggerImpl() override {
ShutdownServer();
}

View File

@@ -25,6 +25,8 @@ enum class DebuggerAction {
class DebuggerBackend {
public:
virtual ~DebuggerBackend() = default;
/**
* Can be invoked from a callback to synchronously wait for more data.
* Will return as soon as least one byte is received. Reads up to 4096 bytes.
@@ -52,6 +54,8 @@ class DebuggerFrontend {
public:
explicit DebuggerFrontend(DebuggerBackend& backend_) : backend{backend_} {}
virtual ~DebuggerFrontend() = default;
/**
* Called after the client has successfully connected to the port.
*/

View File

@@ -34,6 +34,65 @@ constexpr char GDB_STUB_REPLY_ERR[] = "E01";
constexpr char GDB_STUB_REPLY_OK[] = "OK";
constexpr char GDB_STUB_REPLY_EMPTY[] = "";
static u8 CalculateChecksum(std::string_view data) {
return std::accumulate(data.begin(), data.end(), u8{0},
[](u8 lhs, u8 rhs) { return static_cast<u8>(lhs + rhs); });
}
static std::string EscapeGDB(std::string_view data) {
std::string escaped;
escaped.reserve(data.size());
for (char c : data) {
switch (c) {
case '#':
escaped += "}\x03";
break;
case '$':
escaped += "}\x04";
break;
case '*':
escaped += "}\x0a";
break;
case '}':
escaped += "}\x5d";
break;
default:
escaped += c;
break;
}
}
return escaped;
}
static std::string EscapeXML(std::string_view data) {
std::string escaped;
escaped.reserve(data.size());
for (char c : data) {
switch (c) {
case '&':
escaped += "&amp;";
break;
case '"':
escaped += "&quot;";
break;
case '<':
escaped += "&lt;";
break;
case '>':
escaped += "&gt;";
break;
default:
escaped += c;
break;
}
}
return escaped;
}
GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_)
: DebuggerFrontend(backend_), system{system_} {
if (system.CurrentProcess()->Is64BitProcess()) {
@@ -255,6 +314,80 @@ void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction
}
}
// Structure offsets are from Atmosphere
// See osdbg_thread_local_region.os.horizon.hpp and osdbg_thread_type.os.horizon.hpp
static std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory& memory,
const Kernel::KThread* thread) {
// Read thread type from TLS
const VAddr tls_thread_type{memory.Read32(thread->GetTLSAddress() + 0x1fc)};
const VAddr argument_thread_type{thread->GetArgument()};
if (argument_thread_type && tls_thread_type != argument_thread_type) {
// Probably not created by nnsdk, no name available.
return std::nullopt;
}
if (!tls_thread_type) {
return std::nullopt;
}
const u16 version{memory.Read16(tls_thread_type + 0x26)};
VAddr name_pointer{};
if (version == 1) {
name_pointer = memory.Read32(tls_thread_type + 0xe4);
} else {
name_pointer = memory.Read32(tls_thread_type + 0xe8);
}
if (!name_pointer) {
// No name provided.
return std::nullopt;
}
return memory.ReadCString(name_pointer, 256);
}
static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& memory,
const Kernel::KThread* thread) {
// Read thread type from TLS
const VAddr tls_thread_type{memory.Read64(thread->GetTLSAddress() + 0x1f8)};
const VAddr argument_thread_type{thread->GetArgument()};
if (argument_thread_type && tls_thread_type != argument_thread_type) {
// Probably not created by nnsdk, no name available.
return std::nullopt;
}
if (!tls_thread_type) {
return std::nullopt;
}
const u16 version{memory.Read16(tls_thread_type + 0x46)};
VAddr name_pointer{};
if (version == 1) {
name_pointer = memory.Read64(tls_thread_type + 0x1a0);
} else {
name_pointer = memory.Read64(tls_thread_type + 0x1a8);
}
if (!name_pointer) {
// No name provided.
return std::nullopt;
}
return memory.ReadCString(name_pointer, 256);
}
static std::optional<std::string> GetThreadName(Core::System& system,
const Kernel::KThread* thread) {
if (system.CurrentProcess()->Is64BitProcess()) {
return GetNameFromThreadType64(system.Memory(), thread);
} else {
return GetNameFromThreadType32(system.Memory(), thread);
}
}
static std::string_view GetThreadWaitReason(const Kernel::KThread* thread) {
switch (thread->GetWaitReasonForDebugging()) {
case Kernel::ThreadWaitReasonForDebugging::Sleep:
@@ -289,6 +422,18 @@ static std::string GetThreadState(const Kernel::KThread* thread) {
}
}
static std::string PaginateBuffer(std::string_view buffer, std::string_view request) {
const auto amount{request.substr(request.find(',') + 1)};
const auto offset_val{static_cast<u64>(strtoll(request.data(), nullptr, 16))};
const auto amount_val{static_cast<u64>(strtoll(amount.data(), nullptr, 16))};
if (offset_val + amount_val > buffer.size()) {
return fmt::format("l{}", buffer.substr(offset_val));
} else {
return fmt::format("m{}", buffer.substr(offset_val, amount_val));
}
}
void GDBStub::HandleQuery(std::string_view command) {
if (command.starts_with("TStatus")) {
// no tracepoint support
@@ -297,18 +442,8 @@ void GDBStub::HandleQuery(std::string_view command) {
SendReply("PacketSize=4000;qXfer:features:read+;qXfer:threads:read+;qXfer:libraries:read+;"
"vContSupported+;QStartNoAckMode+");
} else if (command.starts_with("Xfer:features:read:target.xml:")) {
const auto offset{command.substr(30)};
const auto amount{command.substr(command.find(',') + 1)};
const auto offset_val{static_cast<u64>(strtoll(offset.data(), nullptr, 16))};
const auto amount_val{static_cast<u64>(strtoll(amount.data(), nullptr, 16))};
const auto target_xml{arch->GetTargetXML()};
if (offset_val + amount_val > target_xml.size()) {
SendReply("l" + target_xml.substr(offset_val));
} else {
SendReply("m" + target_xml.substr(offset_val, amount_val));
}
SendReply(PaginateBuffer(target_xml, command.substr(30)));
} else if (command.starts_with("Offsets")) {
Loader::AppLoader::Modules modules;
system.GetAppLoader().ReadNSOModules(modules);
@@ -321,6 +456,20 @@ void GDBStub::HandleQuery(std::string_view command) {
SendReply(fmt::format("TextSeg={:x}",
system.CurrentProcess()->PageTable().GetCodeRegionStart()));
}
} else if (command.starts_with("Xfer:libraries:read::")) {
Loader::AppLoader::Modules modules;
system.GetAppLoader().ReadNSOModules(modules);
std::string buffer;
buffer += R"(<?xml version="1.0"?>)";
buffer += "<library-list>";
for (const auto& [base, name] : modules) {
buffer += fmt::format(R"(<library name="{}"><segment address="{:#x}"/></library>)",
EscapeXML(name), base);
}
buffer += "</library-list>";
SendReply(PaginateBuffer(buffer, command.substr(21)));
} else if (command.starts_with("fThreadInfo")) {
// beginning of list
const auto& threads = system.GlobalSchedulerContext().GetThreadList();
@@ -332,20 +481,26 @@ void GDBStub::HandleQuery(std::string_view command) {
} else if (command.starts_with("sThreadInfo")) {
// end of list
SendReply("l");
} else if (command.starts_with("Xfer:threads:read")) {
} else if (command.starts_with("Xfer:threads:read::")) {
std::string buffer;
buffer += R"(l<?xml version="1.0"?>)";
buffer += R"(<?xml version="1.0"?>)";
buffer += "<threads>";
const auto& threads = system.GlobalSchedulerContext().GetThreadList();
for (const auto& thread : threads) {
buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="Thread {:d}">{}</thread>)",
for (const auto* thread : threads) {
auto thread_name{GetThreadName(system, thread)};
if (!thread_name) {
thread_name = fmt::format("Thread {:d}", thread->GetThreadID());
}
buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="{}">{}</thread>)",
thread->GetThreadID(), thread->GetActiveCore(),
thread->GetThreadID(), GetThreadState(thread));
EscapeXML(*thread_name), GetThreadState(thread));
}
buffer += "</threads>";
SendReply(buffer);
SendReply(PaginateBuffer(buffer, command.substr(19)));
} else if (command.starts_with("Attached")) {
SendReply("0");
} else if (command.starts_with("StartNoAckMode")) {
@@ -438,14 +593,10 @@ std::optional<std::string> GDBStub::DetachCommand() {
return data.substr(1, data.size() - 4);
}
u8 GDBStub::CalculateChecksum(std::string_view data) {
return static_cast<u8>(
std::accumulate(data.begin(), data.end(), u8{0}, [](u8 lhs, u8 rhs) { return lhs + rhs; }));
}
void GDBStub::SendReply(std::string_view data) {
const auto output{
fmt::format("{}{}{}{:02x}", GDB_STUB_START, data, GDB_STUB_END, CalculateChecksum(data))};
const auto escaped{EscapeGDB(data)};
const auto output{fmt::format("{}{}{}{:02x}", GDB_STUB_START, escaped, GDB_STUB_END,
CalculateChecksum(escaped))};
LOG_TRACE(Debug_GDBStub, "Writing reply: {}", output);
// C++ string support is complete rubbish

View File

@@ -19,7 +19,7 @@ class System;
class GDBStub : public DebuggerFrontend {
public:
explicit GDBStub(DebuggerBackend& backend, Core::System& system);
~GDBStub();
~GDBStub() override;
void Connected() override;
void Stopped(Kernel::KThread* thread) override;
@@ -34,7 +34,6 @@ private:
std::optional<std::string> DetachCommand();
Kernel::KThread* GetThreadByID(u64 thread_id);
static u8 CalculateChecksum(std::string_view data);
void SendReply(std::string_view data);
void SendStatus(char status);

View File

@@ -46,6 +46,7 @@ std::string GDBStubA64::GetTargetXML() const {
R"(<?xml version="1.0"?>
<!DOCTYPE target SYSTEM "gdb-target.dtd">
<target version="1.0">
<architecture>aarch64</architecture>
<feature name="org.gnu.gdb.aarch64.core">
<reg name="x0" bitsize="64"/>
<reg name="x1" bitsize="64"/>
@@ -80,7 +81,7 @@ std::string GDBStubA64::GetTargetXML() const {
<reg name="x30" bitsize="64"/>
<reg name="sp" bitsize="64" type="data_ptr"/>
<reg name="pc" bitsize="64" type="code_ptr"/>
<flags id="pstate_flags" size="4">
<flags id="cpsr_flags" size="4">
<field name="SP" start="0" end="0"/>
<field name="" start="1" end="1"/>
<field name="EL" start="2" end="3"/>
@@ -97,9 +98,84 @@ std::string GDBStubA64::GetTargetXML() const {
<field name="Z" start="30" end="30"/>
<field name="N" start="31" end="31"/>
</flags>
<reg name="pstate" bitsize="32" type="pstate_flags"/>
<reg name="cpsr" bitsize="32" type="cpsr_flags"/>
</feature>
<feature name="org.gnu.gdb.aarch64.fpu">
<vector id="v2d" type="ieee_double" count="2"/>
<vector id="v2u" type="uint64" count="2"/>
<vector id="v2i" type="int64" count="2"/>
<vector id="v4f" type="ieee_single" count="4"/>
<vector id="v4u" type="uint32" count="4"/>
<vector id="v4i" type="int32" count="4"/>
<vector id="v8u" type="uint16" count="8"/>
<vector id="v8i" type="int16" count="8"/>
<vector id="v16u" type="uint8" count="16"/>
<vector id="v16i" type="int8" count="16"/>
<vector id="v1u" type="uint128" count="1"/>
<vector id="v1i" type="int128" count="1"/>
<union id="vnd">
<field name="f" type="v2d"/>
<field name="u" type="v2u"/>
<field name="s" type="v2i"/>
</union>
<union id="vns">
<field name="f" type="v4f"/>
<field name="u" type="v4u"/>
<field name="s" type="v4i"/>
</union>
<union id="vnh">
<field name="u" type="v8u"/>
<field name="s" type="v8i"/>
</union>
<union id="vnb">
<field name="u" type="v16u"/>
<field name="s" type="v16i"/>
</union>
<union id="vnq">
<field name="u" type="v1u"/>
<field name="s" type="v1i"/>
</union>
<union id="aarch64v">
<field name="d" type="vnd"/>
<field name="s" type="vns"/>
<field name="h" type="vnh"/>
<field name="b" type="vnb"/>
<field name="q" type="vnq"/>
</union>
<reg name="v0" bitsize="128" type="aarch64v" regnum="34"/>
<reg name="v1" bitsize="128" type="aarch64v" />
<reg name="v2" bitsize="128" type="aarch64v" />
<reg name="v3" bitsize="128" type="aarch64v" />
<reg name="v4" bitsize="128" type="aarch64v" />
<reg name="v5" bitsize="128" type="aarch64v" />
<reg name="v6" bitsize="128" type="aarch64v" />
<reg name="v7" bitsize="128" type="aarch64v" />
<reg name="v8" bitsize="128" type="aarch64v" />
<reg name="v9" bitsize="128" type="aarch64v" />
<reg name="v10" bitsize="128" type="aarch64v"/>
<reg name="v11" bitsize="128" type="aarch64v"/>
<reg name="v12" bitsize="128" type="aarch64v"/>
<reg name="v13" bitsize="128" type="aarch64v"/>
<reg name="v14" bitsize="128" type="aarch64v"/>
<reg name="v15" bitsize="128" type="aarch64v"/>
<reg name="v16" bitsize="128" type="aarch64v"/>
<reg name="v17" bitsize="128" type="aarch64v"/>
<reg name="v18" bitsize="128" type="aarch64v"/>
<reg name="v19" bitsize="128" type="aarch64v"/>
<reg name="v20" bitsize="128" type="aarch64v"/>
<reg name="v21" bitsize="128" type="aarch64v"/>
<reg name="v22" bitsize="128" type="aarch64v"/>
<reg name="v23" bitsize="128" type="aarch64v"/>
<reg name="v24" bitsize="128" type="aarch64v"/>
<reg name="v25" bitsize="128" type="aarch64v"/>
<reg name="v26" bitsize="128" type="aarch64v"/>
<reg name="v27" bitsize="128" type="aarch64v"/>
<reg name="v28" bitsize="128" type="aarch64v"/>
<reg name="v29" bitsize="128" type="aarch64v"/>
<reg name="v30" bitsize="128" type="aarch64v"/>
<reg name="v31" bitsize="128" type="aarch64v"/>
<reg name="fpsr" bitsize="32"/>
<reg name="fpcr" bitsize="32"/>
</feature>
</target>)";
@@ -121,12 +197,12 @@ std::string GDBStubA64::RegRead(const Kernel::KThread* thread, size_t id) const
return ValueToHex(context.pc);
} else if (id == PSTATE_REGISTER) {
return ValueToHex(context.pstate);
} else if (id >= Q0_REGISTER && id < FPCR_REGISTER) {
} else if (id >= Q0_REGISTER && id < FPSR_REGISTER) {
return ValueToHex(fprs[id - Q0_REGISTER]);
} else if (id == FPCR_REGISTER) {
return ValueToHex(context.fpcr);
} else if (id == FPSR_REGISTER) {
return ValueToHex(context.fpsr);
} else if (id == FPCR_REGISTER) {
return ValueToHex(context.fpcr);
} else {
return "";
}
@@ -145,12 +221,12 @@ void GDBStubA64::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v
context.pc = HexToValue<u64>(value);
} else if (id == PSTATE_REGISTER) {
context.pstate = HexToValue<u32>(value);
} else if (id >= Q0_REGISTER && id < FPCR_REGISTER) {
} else if (id >= Q0_REGISTER && id < FPSR_REGISTER) {
context.vector_registers[id - Q0_REGISTER] = HexToValue<u128>(value);
} else if (id == FPCR_REGISTER) {
context.fpcr = HexToValue<u32>(value);
} else if (id == FPSR_REGISTER) {
context.fpsr = HexToValue<u32>(value);
} else if (id == FPCR_REGISTER) {
context.fpcr = HexToValue<u32>(value);
}
}
@@ -195,6 +271,7 @@ std::string GDBStubA32::GetTargetXML() const {
R"(<?xml version="1.0"?>
<!DOCTYPE target SYSTEM "gdb-target.dtd">
<target version="1.0">
<architecture>arm</architecture>
<feature name="org.gnu.gdb.arm.core">
<reg name="r0" bitsize="32" type="uint32"/>
<reg name="r1" bitsize="32" type="uint32"/>

View File

@@ -40,8 +40,8 @@ private:
static constexpr u32 PC_REGISTER = 32;
static constexpr u32 PSTATE_REGISTER = 33;
static constexpr u32 Q0_REGISTER = 34;
static constexpr u32 FPCR_REGISTER = 66;
static constexpr u32 FPSR_REGISTER = 67;
static constexpr u32 FPSR_REGISTER = 66;
static constexpr u32 FPCR_REGISTER = 67;
};
class GDBStubA32 final : public GDBStubArch {

View File

@@ -198,6 +198,10 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s
resource_limit_release_hint = false;
cpu_time = 0;
// Set debug context.
stack_top = user_stack_top;
argument = arg;
// Clear our stack parameters.
std::memset(static_cast<void*>(std::addressof(GetStackParameters())), 0,
sizeof(StackParameters));

View File

@@ -660,6 +660,14 @@ public:
void IfDummyThreadTryWait();
void IfDummyThreadEndWait();
[[nodiscard]] uintptr_t GetArgument() const {
return argument;
}
[[nodiscard]] VAddr GetUserStackTop() const {
return stack_top;
}
private:
static constexpr size_t PriorityInheritanceCountMax = 10;
union SyncObjectBuffer {
@@ -791,6 +799,8 @@ private:
std::vector<KSynchronizationObject*> wait_objects_for_debugging;
VAddr mutex_wait_address_for_debugging{};
ThreadWaitReasonForDebugging wait_reason_for_debugging{};
uintptr_t argument;
VAddr stack_top;
public:
using ConditionVariableThreadTreeType = ConditionVariableThreadTree;

View File

@@ -5,7 +5,9 @@
#include "core/core_timing.h"
#include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/hid/errors.h"
#include "core/hle/service/hid/irs.h"
namespace Service::HID {
@@ -38,21 +40,32 @@ IRS::IRS(Core::System& system_) : ServiceFramework{system_, "irs"} {
}
void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}",
applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_IRS, "called");
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_DEBUG(Service_IRS, "called, applet_resource_user_id={}", applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
@@ -60,35 +73,109 @@ void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
}
void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
struct Parameters {
IrCameraHandle camera_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
struct Parameters {
IrCameraHandle camera_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
PackedMomentProcessorConfig processor_config;
};
static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
struct Parameters {
IrCameraHandle camera_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
PackedClusteringProcessorConfig processor_config;
};
static_assert(sizeof(Parameters) == 0x40, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
struct Parameters {
IrCameraHandle camera_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
PackedImageTransferProcessorConfig processor_config;
u32 transfer_memory_size;
};
static_assert(sizeof(Parameters) == 0x30, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
const auto t_mem_handle{ctx.GetCopyHandle(0)};
auto t_mem =
system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle);
LOG_WARNING(Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, transfer_memory_size={}, "
"applet_resource_user_id={}",
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
parameters.transfer_memory_size, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
struct Parameters {
IrCameraHandle camera_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 5};
rb.Push(ResultSuccess);
@@ -97,71 +184,195 @@ void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) {
}
void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
const auto camera_handle{rp.PopRaw<IrCameraHandle>()};
const auto processor_config{rp.PopRaw<PackedTeraPluginProcessorConfig>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, mode={}, mcu_version={}.{}, "
"applet_resource_user_id={}",
camera_handle.npad_type, camera_handle.npad_id, processor_config.mode,
processor_config.required_mcu_version.major,
processor_config.required_mcu_version.minor, applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
if (npad_id > Core::HID::NpadIdType::Player8 && npad_id != Core::HID::NpadIdType::Invalid &&
npad_id != Core::HID::NpadIdType::Handheld) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(InvalidNpadId);
return;
}
IrCameraHandle camera_handle{
.npad_id = static_cast<u8>(NpadIdTypeToIndex(npad_id)),
.npad_type = Core::HID::NpadStyleIndex::None,
};
LOG_WARNING(Service_IRS, "(STUBBED) called, npad_id={}, camera_npad_id={}, camera_npad_type={}",
npad_id, camera_handle.npad_id, camera_handle.npad_type);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushRaw<u32>(device_handle);
rb.PushRaw(camera_handle);
}
void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
const auto camera_handle{rp.PopRaw<IrCameraHandle>()};
const auto processor_config{rp.PopRaw<PackedPointingProcessorConfig>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(
Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, mcu_version={}.{}, applet_resource_user_id={}",
camera_handle.npad_type, camera_handle.npad_id, processor_config.required_mcu_version.major,
processor_config.required_mcu_version.minor, applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
struct Parameters {
IrCameraHandle camera_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
const auto camera_handle{rp.PopRaw<IrCameraHandle>()};
const auto mcu_version{rp.PopRaw<PackedMcuVersion>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(
Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}, mcu_version={}.{}",
camera_handle.npad_type, camera_handle.npad_id, applet_resource_user_id, mcu_version.major,
mcu_version.minor);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
struct Parameters {
IrCameraHandle camera_handle;
PackedFunctionLevel function_level;
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
struct Parameters {
IrCameraHandle camera_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
PackedImageTransferProcessorExConfig processor_config;
u64 transfer_memory_size;
};
static_assert(sizeof(Parameters) == 0x38, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
const auto t_mem_handle{ctx.GetCopyHandle(0)};
auto t_mem =
system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>(t_mem_handle);
LOG_WARNING(Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, transfer_memory_size={}, "
"applet_resource_user_id={}",
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
parameters.transfer_memory_size, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
const auto camera_handle{rp.PopRaw<IrCameraHandle>()};
const auto processor_config{rp.PopRaw<PackedIrLedProcessorConfig>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, light_target={}, mcu_version={}.{} "
"applet_resource_user_id={}",
camera_handle.npad_type, camera_handle.npad_id, processor_config.light_target,
processor_config.required_mcu_version.major,
processor_config.required_mcu_version.minor, applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
struct Parameters {
IrCameraHandle camera_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_IRS,
"(STUBBED) called, npad_type={}, npad_id={}, applet_resource_user_id={}",
parameters.camera_handle.npad_type, parameters.camera_handle.npad_id,
parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_IRS, "(STUBBED) called");
IPC::RequestParser rp{ctx};
struct Parameters {
PackedFunctionLevel function_level;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_IRS, "(STUBBED) called, function_level={}, applet_resource_user_id={}",
parameters.function_level.function_level, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);

View File

@@ -3,6 +3,7 @@
#pragma once
#include "core/hid/hid_types.h"
#include "core/hle/service/service.h"
namespace Core {
@@ -17,6 +18,235 @@ public:
~IRS() override;
private:
// This is nn::irsensor::IrCameraStatus
enum IrCameraStatus : u32 {
Available,
Unsupported,
Unconnected,
};
// This is nn::irsensor::IrCameraInternalStatus
enum IrCameraInternalStatus : u32 {
Stopped,
FirmwareUpdateNeeded,
Unkown2,
Unkown3,
Unkown4,
FirmwareVersionRequested,
FirmwareVersionIsInvalid,
Ready,
Setting,
};
// This is nn::irsensor::detail::StatusManager::IrSensorMode
enum IrSensorMode : u64 {
None,
MomentProcessor,
ClusteringProcessor,
ImageTransferProcessor,
PointingProcessorMarker,
TeraPluginProcessor,
IrLedProcessor,
};
// This is nn::irsensor::ImageProcessorStatus
enum ImageProcessorStatus : u8 {
stopped,
running,
};
// This is nn::irsensor::ImageTransferProcessorFormat
enum ImageTransferProcessorFormat : u8 {
Size320x240,
Size160x120,
Size80x60,
Size40x30,
Size20x15,
};
// This is nn::irsensor::AdaptiveClusteringMode
enum AdaptiveClusteringMode : u8 {
StaticFov,
DynamicFov,
};
// This is nn::irsensor::AdaptiveClusteringTargetDistance
enum AdaptiveClusteringTargetDistance : u8 {
Near,
Middle,
Far,
};
// This is nn::irsensor::IrsHandAnalysisMode
enum IrsHandAnalysisMode : u8 {
Silhouette,
Image,
SilhoueteAndImage,
SilhuetteOnly,
};
// This is nn::irsensor::IrSensorFunctionLevel
enum IrSensorFunctionLevel : u8 {
unknown0,
unknown1,
unknown2,
unknown3,
unknown4,
};
// This is nn::irsensor::IrCameraHandle
struct IrCameraHandle {
u8 npad_id{};
Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None};
INSERT_PADDING_BYTES(2);
};
static_assert(sizeof(IrCameraHandle) == 4, "IrCameraHandle is an invalid size");
struct IrsRect {
s16 x;
s16 y;
s16 width;
s16 height;
};
// This is nn::irsensor::PackedMcuVersion
struct PackedMcuVersion {
u16 major;
u16 minor;
};
static_assert(sizeof(PackedMcuVersion) == 4, "PackedMcuVersion is an invalid size");
// This is nn::irsensor::MomentProcessorConfig
struct MomentProcessorConfig {
u64 exposire_time;
u8 light_target;
u8 gain;
u8 is_negative_used;
INSERT_PADDING_BYTES(7);
IrsRect window_of_interest;
u8 preprocess;
u8 preprocess_intensity_threshold;
INSERT_PADDING_BYTES(5);
};
static_assert(sizeof(MomentProcessorConfig) == 0x28,
"MomentProcessorConfig is an invalid size");
// This is nn::irsensor::PackedMomentProcessorConfig
struct PackedMomentProcessorConfig {
u64 exposire_time;
u8 light_target;
u8 gain;
u8 is_negative_used;
INSERT_PADDING_BYTES(5);
IrsRect window_of_interest;
PackedMcuVersion required_mcu_version;
u8 preprocess;
u8 preprocess_intensity_threshold;
INSERT_PADDING_BYTES(2);
};
static_assert(sizeof(PackedMomentProcessorConfig) == 0x20,
"PackedMomentProcessorConfig is an invalid size");
// This is nn::irsensor::ClusteringProcessorConfig
struct ClusteringProcessorConfig {
u64 exposire_time;
u32 light_target;
u32 gain;
u8 is_negative_used;
INSERT_PADDING_BYTES(7);
IrsRect window_of_interest;
u32 pixel_count_min;
u32 pixel_count_max;
u32 object_intensity_min;
u8 is_external_light_filter_enabled;
INSERT_PADDING_BYTES(3);
};
static_assert(sizeof(ClusteringProcessorConfig) == 0x30,
"ClusteringProcessorConfig is an invalid size");
// This is nn::irsensor::PackedClusteringProcessorConfig
struct PackedClusteringProcessorConfig {
u64 exposire_time;
u8 light_target;
u8 gain;
u8 is_negative_used;
INSERT_PADDING_BYTES(5);
IrsRect window_of_interest;
PackedMcuVersion required_mcu_version;
u32 pixel_count_min;
u32 pixel_count_max;
u32 object_intensity_min;
u8 is_external_light_filter_enabled;
INSERT_PADDING_BYTES(2);
};
static_assert(sizeof(PackedClusteringProcessorConfig) == 0x30,
"PackedClusteringProcessorConfig is an invalid size");
// This is nn::irsensor::PackedImageTransferProcessorConfig
struct PackedImageTransferProcessorConfig {
u64 exposire_time;
u8 light_target;
u8 gain;
u8 is_negative_used;
INSERT_PADDING_BYTES(5);
PackedMcuVersion required_mcu_version;
u8 format;
INSERT_PADDING_BYTES(3);
};
static_assert(sizeof(PackedImageTransferProcessorConfig) == 0x18,
"PackedImageTransferProcessorConfig is an invalid size");
// This is nn::irsensor::PackedTeraPluginProcessorConfig
struct PackedTeraPluginProcessorConfig {
PackedMcuVersion required_mcu_version;
u8 mode;
INSERT_PADDING_BYTES(3);
};
static_assert(sizeof(PackedTeraPluginProcessorConfig) == 0x8,
"PackedTeraPluginProcessorConfig is an invalid size");
// This is nn::irsensor::PackedPointingProcessorConfig
struct PackedPointingProcessorConfig {
IrsRect window_of_interest;
PackedMcuVersion required_mcu_version;
};
static_assert(sizeof(PackedPointingProcessorConfig) == 0xC,
"PackedPointingProcessorConfig is an invalid size");
// This is nn::irsensor::PackedFunctionLevel
struct PackedFunctionLevel {
IrSensorFunctionLevel function_level;
INSERT_PADDING_BYTES(3);
};
static_assert(sizeof(PackedFunctionLevel) == 0x4, "PackedFunctionLevel is an invalid size");
// This is nn::irsensor::PackedImageTransferProcessorExConfig
struct PackedImageTransferProcessorExConfig {
u64 exposire_time;
u8 light_target;
u8 gain;
u8 is_negative_used;
INSERT_PADDING_BYTES(5);
PackedMcuVersion required_mcu_version;
ImageTransferProcessorFormat origin_format;
ImageTransferProcessorFormat trimming_format;
u16 trimming_start_x;
u16 trimming_start_y;
u8 is_external_light_filter_enabled;
INSERT_PADDING_BYTES(3);
};
static_assert(sizeof(PackedImageTransferProcessorExConfig) == 0x20,
"PackedImageTransferProcessorExConfig is an invalid size");
// This is nn::irsensor::PackedIrLedProcessorConfig
struct PackedIrLedProcessorConfig {
PackedMcuVersion required_mcu_version;
u8 light_target;
INSERT_PADDING_BYTES(3);
};
static_assert(sizeof(PackedIrLedProcessorConfig) == 0x8,
"PackedIrLedProcessorConfig is an invalid size");
void ActivateIrsensor(Kernel::HLERequestContext& ctx);
void DeactivateIrsensor(Kernel::HLERequestContext& ctx);
void GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx);
@@ -35,8 +265,6 @@ private:
void RunIrLedProcessor(Kernel::HLERequestContext& ctx);
void StopImageProcessorAsync(Kernel::HLERequestContext& ctx);
void ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx);
const u32 device_handle{0xABCD};
};
class IRS_SYS final : public ServiceFramework<IRS_SYS> {

View File

@@ -11,10 +11,13 @@
#include "common/alignment.h"
#include "common/common_funcs.h"
#include "common/div_ceil.h"
#include "common/elf.h"
#include "common/logging/log.h"
#include "core/hle/service/jit/jit_context.h"
#include "core/memory.h"
using namespace Common::ELF;
namespace Service::JIT {
constexpr std::array<u8, 8> SVC0_ARM64 = {
@@ -26,25 +29,6 @@ constexpr std::array HELPER_FUNCTIONS{
"_stop", "_resolve", "_panic", "memcpy", "memmove", "memset",
};
struct Elf64_Dyn {
u64 d_tag;
u64 d_un;
};
struct Elf64_Rela {
u64 r_offset;
u64 r_info;
s64 r_addend;
};
static constexpr u32 Elf64_RelaType(const Elf64_Rela* rela) {
return static_cast<u32>(rela->r_info);
}
constexpr int DT_RELA = 7; /* Address of Rela relocs */
constexpr int DT_RELASZ = 8; /* Total size of Rela relocs */
constexpr int R_AARCH64_RELATIVE = 1027; /* Adjust by program base. */
constexpr size_t STACK_ALIGN = 16;
class JITContextImpl;
@@ -206,17 +190,17 @@ public:
if (!dyn.d_tag) {
break;
}
if (dyn.d_tag == DT_RELA) {
rela_dyn = dyn.d_un;
if (dyn.d_tag == ElfDtRela) {
rela_dyn = dyn.d_un.d_ptr;
}
if (dyn.d_tag == DT_RELASZ) {
num_rela = dyn.d_un / sizeof(Elf64_Rela);
if (dyn.d_tag == ElfDtRelasz) {
num_rela = dyn.d_un.d_val / sizeof(Elf64_Rela);
}
}
for (size_t i = 0; i < num_rela; i++) {
const auto rela{callbacks->ReadMemory<Elf64_Rela>(rela_dyn + i * sizeof(Elf64_Rela))};
if (Elf64_RelaType(&rela) != R_AARCH64_RELATIVE) {
if (Elf64RelType(rela.r_info) != ElfAArch64Relative) {
continue;
}
const VAddr contents{callbacks->MemoryRead64(rela.r_offset)};

View File

@@ -6,6 +6,7 @@
#include <memory>
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/elf.h"
#include "common/logging/log.h"
#include "core/hle/kernel/code_set.h"
#include "core/hle/kernel/k_page_table.h"
@@ -13,159 +14,7 @@
#include "core/loader/elf.h"
#include "core/memory.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// ELF Header Constants
// File type
enum ElfType {
ET_NONE = 0,
ET_REL = 1,
ET_EXEC = 2,
ET_DYN = 3,
ET_CORE = 4,
ET_LOPROC = 0xFF00,
ET_HIPROC = 0xFFFF,
};
// Machine/Architecture
enum ElfMachine {
EM_NONE = 0,
EM_M32 = 1,
EM_SPARC = 2,
EM_386 = 3,
EM_68K = 4,
EM_88K = 5,
EM_860 = 7,
EM_MIPS = 8
};
// File version
#define EV_NONE 0
#define EV_CURRENT 1
// Identification index
#define EI_MAG0 0
#define EI_MAG1 1
#define EI_MAG2 2
#define EI_MAG3 3
#define EI_CLASS 4
#define EI_DATA 5
#define EI_VERSION 6
#define EI_PAD 7
#define EI_NIDENT 16
// Sections constants
// Section types
#define SHT_NULL 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_HASH 5
#define SHT_DYNAMIC 6
#define SHT_NOTE 7
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_SHLIB 10
#define SHT_DYNSYM 11
#define SHT_LOPROC 0x70000000
#define SHT_HIPROC 0x7FFFFFFF
#define SHT_LOUSER 0x80000000
#define SHT_HIUSER 0xFFFFFFFF
// Section flags
enum ElfSectionFlags {
SHF_WRITE = 0x1,
SHF_ALLOC = 0x2,
SHF_EXECINSTR = 0x4,
SHF_MASKPROC = 0xF0000000,
};
// Segment types
#define PT_NULL 0
#define PT_LOAD 1
#define PT_DYNAMIC 2
#define PT_INTERP 3
#define PT_NOTE 4
#define PT_SHLIB 5
#define PT_PHDR 6
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7FFFFFFF
// Segment flags
#define PF_X 0x1
#define PF_W 0x2
#define PF_R 0x4
#define PF_MASKPROC 0xF0000000
typedef unsigned int Elf32_Addr;
typedef unsigned short Elf32_Half;
typedef unsigned int Elf32_Off;
typedef signed int Elf32_Sword;
typedef unsigned int Elf32_Word;
////////////////////////////////////////////////////////////////////////////////////////////////////
// ELF file header
struct Elf32_Ehdr {
unsigned char e_ident[EI_NIDENT];
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
};
// Section header
struct Elf32_Shdr {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
};
// Segment header
struct Elf32_Phdr {
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
};
// Symbol table entry
struct Elf32_Sym {
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
};
// Relocation entries
struct Elf32_Rel {
Elf32_Addr r_offset;
Elf32_Word r_info;
};
using namespace Common::ELF;
////////////////////////////////////////////////////////////////////////////////////////////////////
// ElfReader class
@@ -193,11 +42,11 @@ public:
}
// Quick accessors
ElfType GetType() const {
return (ElfType)(header->e_type);
u16 GetType() const {
return header->e_type;
}
ElfMachine GetMachine() const {
return (ElfMachine)(header->e_machine);
u16 GetMachine() const {
return header->e_machine;
}
VAddr GetEntryPoint() const {
return entryPoint;
@@ -220,13 +69,13 @@ public:
const u8* GetSectionDataPtr(int section) const {
if (section < 0 || section >= header->e_shnum)
return nullptr;
if (sections[section].sh_type != SHT_NOBITS)
if (sections[section].sh_type != ElfShtNobits)
return GetPtr(sections[section].sh_offset);
else
return nullptr;
}
bool IsCodeSection(int section) const {
return sections[section].sh_type == SHT_PROGBITS;
return sections[section].sh_type == ElfShtProgBits;
}
const u8* GetSegmentPtr(int segment) {
return GetPtr(segments[segment].p_offset);
@@ -256,7 +105,7 @@ ElfReader::ElfReader(void* ptr) {
}
const char* ElfReader::GetSectionName(int section) const {
if (sections[section].sh_type == SHT_NULL)
if (sections[section].sh_type == ElfShtNull)
return nullptr;
int name_offset = sections[section].sh_name;
@@ -272,7 +121,7 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) {
LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx);
// Should we relocate?
relocate = (header->e_type != ET_EXEC);
relocate = (header->e_type != ElfTypeExec);
if (relocate) {
LOG_DEBUG(Loader, "Relocatable module");
@@ -288,7 +137,7 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) {
u64 total_image_size = 0;
for (unsigned int i = 0; i < header->e_phnum; ++i) {
const Elf32_Phdr* p = &segments[i];
if (p->p_type == PT_LOAD) {
if (p->p_type == ElfPtLoad) {
total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF;
}
}
@@ -303,14 +152,14 @@ Kernel::CodeSet ElfReader::LoadInto(VAddr vaddr) {
LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type,
p->p_vaddr, p->p_filesz, p->p_memsz);
if (p->p_type == PT_LOAD) {
if (p->p_type == ElfPtLoad) {
Kernel::CodeSet::Segment* codeset_segment;
u32 permission_flags = p->p_flags & (PF_R | PF_W | PF_X);
if (permission_flags == (PF_R | PF_X)) {
u32 permission_flags = p->p_flags & (ElfPfRead | ElfPfWrite | ElfPfExec);
if (permission_flags == (ElfPfRead | ElfPfExec)) {
codeset_segment = &codeset.CodeSegment();
} else if (permission_flags == (PF_R)) {
} else if (permission_flags == (ElfPfRead)) {
codeset_segment = &codeset.RODataSegment();
} else if (permission_flags == (PF_R | PF_W)) {
} else if (permission_flags == (ElfPfRead | ElfPfWrite)) {
codeset_segment = &codeset.DataSegment();
} else {
LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id {} with flags {:X}", i,

View File

@@ -595,8 +595,8 @@ void Maxwell3D::DrawArrays() {
std::optional<u64> Maxwell3D::GetQueryResult() {
switch (regs.query.query_get.select) {
case Regs::QuerySelect::Zero:
return 0;
case Regs::QuerySelect::Payload:
return regs.query.query_sequence;
case Regs::QuerySelect::SamplesPassed:
// Deferred.
rasterizer->Query(regs.query.QueryAddress(), QueryType::SamplesPassed,

View File

@@ -93,7 +93,7 @@ public:
};
enum class QuerySelect : u32 {
Zero = 0,
Payload = 0,
TimeElapsed = 2,
TransformFeedbackPrimitivesGenerated = 11,
PrimitivesGenerated = 18,

View File

@@ -198,6 +198,31 @@ static void RemoveCachedContents() {
Common::FS::RemoveDirRecursively(offline_system_data);
}
static QString PrettyProductName() {
#ifdef _WIN32
// After Windows 10 Version 2004, Microsoft decided to switch to a different notation: 20H2
// With that notation change they changed the registry key used to denote the current version
QSettings windows_registry(
QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"),
QSettings::NativeFormat);
const QString release_id = windows_registry.value(QStringLiteral("ReleaseId")).toString();
if (release_id == QStringLiteral("2009")) {
const u32 current_build = windows_registry.value(QStringLiteral("CurrentBuild")).toUInt();
const QString display_version =
windows_registry.value(QStringLiteral("DisplayVersion")).toString();
const u32 ubr = windows_registry.value(QStringLiteral("UBR")).toUInt();
u32 version = 10;
if (current_build >= 22000) {
version = 11;
}
return QStringLiteral("Windows %1 Version %2 (Build %3.%4)")
.arg(QString::number(version), display_version, QString::number(current_build),
QString::number(ubr));
}
#endif
return QSysInfo::prettyProductName();
}
GMainWindow::GMainWindow()
: ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()},
input_subsystem{std::make_shared<InputCommon::InputSubsystem>()},
@@ -259,7 +284,7 @@ GMainWindow::GMainWindow()
}
LOG_INFO(Frontend, "Host CPU: {}", cpu_string);
#endif
LOG_INFO(Frontend, "Host OS: {}", QSysInfo::prettyProductName().toStdString());
LOG_INFO(Frontend, "Host OS: {}", PrettyProductName().toStdString());
LOG_INFO(Frontend, "Host RAM: {:.2f} GiB",
Common::GetMemInfo().TotalPhysicalMemory / f64{1_GiB});
LOG_INFO(Frontend, "Host Swap: {:.2f} GiB", Common::GetMemInfo().TotalSwapMemory / f64{1_GiB});
@@ -1015,6 +1040,10 @@ void GMainWindow::SetDefaultUIGeometry() {
void GMainWindow::RestoreUIState() {
setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
restoreGeometry(UISettings::values.geometry);
// Work-around because the games list isn't supposed to be full screen
if (isFullScreen()) {
showNormal();
}
restoreState(UISettings::values.state);
render_window->setWindowFlags(render_window->windowFlags() & ~Qt::FramelessWindowHint);
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);