libtransistor

repository·development·Indexed 42 days ago

https://github.com/reswitched/libtransistor

A userland library for the Nintendo Switch designed to run on physical hardware via Atmosphere or under emulators such as Mephisto, Yuzu, and Ryujinx. It provides C++ abstractions for process lifecycle management (KProcess), memory mapping (MapProcessMemory, MapSharedMemory, MapTransferMemory), and process debugging (DebugActiveProcess).

Tokens
3.5K
Snippets
16
Records
20
Agent score
53%

What's inside libtransistor

  1. Error handling using goto

    development

    The project uses the goto pattern for error handling, similar to the Linux kernel. This pattern reduces code duplication and keeps the primary function logic clear.

    Pattern:

    1. Use goto to jump to error-handling labels.
    2. Name labels after the most recent resource acquired that needs to be freed.
    3. This is particularly effective when functions return a result_t type.
    void func() {
    	result_t r = RESULT_OK;
    	if((r =  sm_init()) != RESULT_OK) { goto fail; }
    	if((r = bsd_init()) != RESULT_OK) { goto fail_sm; }
    
    	// code goes here
    	
    
    bsd_finalize();
    fail_sm:
    	sm_finalize();
    fail:
    	return r;
    }
  2. Coding style and naming conventions

    development

    When contributing to libtransistor, follow these naming and indentation guidelines:

    Naming

    • Use snake_case for identifiers.
    • Type names must end with _t (e.g., result_t).
    • Use descriptive names for most identifiers, but short names are acceptable for small scopes or well-known purposes (e.g., i, j for iterators; x, y, z for coordinates; w, h, l for dimensions).

    Indentation and Alignment

    • Use tabs for indentation. This is a requirement to ensure consistency across different user configurations.
    • Use spaces for alignment. Never use tabs for alignment; use spaces instead to ensure visual consistency across different editor widths.
    • Tabs should not appear on a line after any non-tab character without a specific reason.
  3. Formatting braces, parentheses, and operators

    development

    Follow these rules for whitespace and punctuation:

    Braces and Parentheses

    • Functions/Macros/Keywords: No whitespace between a function call (or macro/keyword like if or sizeof) and its opening parenthesis, and no whitespace between the parenthesis and its contents.
    • Commas: Always follow commas with a space.
    • Curly Brackets: Place the opening curly bracket on the same line as the statement, preceded by a space.
    • If Statements: Always use brackets {} for if statements, even for single lines. This prevents errors and simplifies future modifications.
    • Else/Else If: Place else and else if on the same line as the closing brace } and the following opening brace {.

    Operators

    • Binary/Ternary Operators: Apply whitespace around them to improve readability.
    • Unary/Member Operators: Do not apply whitespace around unary operators or the -> and . operators.
    • Compound Assignment: Keep operators adjacent to the variable (e.g., a+= b;).
    • Pointers: The * symbol should be adjacent to the identifier (e.g., uint64_t *a). When casting, it may be placed next to the type.
    • Casts: Always include a space after a cast.
    void foo(int bar, int baz) {
    	return sizeof(bar);
    }
    
    if(a) {
    	single_statement();
    } else if(b) {
    	another_single_statement();
    } else {
    	two();
    	statements();
    }
    
    return a ? (b ? (c + d) * e-- : -f.g) : h->i;
    
    uint32_t example(uint64_t *a) {
    	return *((uint32_t*) a);
    }
  4. Organizing header files

    development

    Follow these rules for header and implementation file organization:

    • Header Guards: Use #pragma once instead of traditional #ifndef guards.
    • Directory Structure: Header files reside in include/libtransistor/. The directory tree in include/ should match the tree in lib/.
    • Implementation Files: .c files should generally have the same name and reside in the same directory as their corresponding header files.
    • Includes: Include only the specific headers required. Each .c file should include its most relevant header file before any others to ensure dependencies are explicitly satisfied.
    • Convenience Header: libtransistor/nx.h is provided for consumer programs; it should not be used within the library itself.
  5. Install libtransistor

    development

    To install libtransistor, download the latest release archive (libtransistor_vX.X.X.tar.gz or libtransistor_vX.X.X.zip) and extract it.

    It is recommended to extract the archive into /opt/libtransistor/. You must set the LIBTRANSISTOR_HOME environment variable to the path where you extracted the archive to ensure the library can be located by other tools and build systems.

    export LIBTRANSISTOR_HOME=/opt/libtransistor
  6. Build libtransistor on Fedora

    development

    Fedora's default clang and lld may be too old. Use pre-built binaries from llvm.org.

    Example workflow:

    wget -c http://releases.llvm.org/5.0.1/clang+llvm-5.0.1-x86_64-linux-gnu-Fedora27.tar.xz
    tar xpf clang+llvm-5.0.1-x86_64-linux-gnu-Fedora27.tar.xz
    export PATH=`pwd`/clang+llvm-5.0.1-x86_64-linux-gnu-Fedora27/bin:$PATH
    cd libtransistor
    make

    If CMake CXX tests fail, install these dependencies:

    sudo dnf -y install libstdc++-devel gcc-c++.x86_64
    wget -c http://releases.llvm.org/5.0.1/clang+llvm-5.0.1-x86_64-linux-gnu-Fedora27.tar.xz
    tar xpf clang+llvm-5.0.1-x86_64-linux-gnu-Fedora27.tar.xz
    export PATH=`pwd`/clang+llvm-5.0.1-x86_64-linux-gnu-Fedora27/bin:$PATH
    cd libtransistor
    make
  7. Debug libtransistor binaries with GDB

    development

    Since Mephisto provides a GDB stub, you can debug libtransistor binaries by running ctu with the --enable-gdb flag, then connecting via aarch64-none-elf-gdb.

    1. Start the GDB server:
    ./ctu --load-nro <path-to-libtransistor>/build/test/<binary>.nro --enable-gdb
    1. In a new terminal, start GDB and connect to the remote target:
    aarch64-none-elf-gdb
    (gdb) target remote localhost:24689
    1. Load the symbol file (the .nro.so file) to enable proper debugging:
    (gdb) add-symbol-file <path-to-libtransistor>/build/test/<binary>.nro.so 0x7100000000 -s .bss 0x7100000000
    ./ctu --load-nro <path-to-libtransistor>/build/test/<binary>.nro --enable-gdb
    
    aarch64-none-elf-gdb
    (gdb) target remote localhost:24689
    (gdb) add-symbol-file <path-to-libtransistor>/build/test/<binary>.nro.so 0x7100000000 -s .bss 0x7100000000
  8. Build libtransistor on Arch Linux

    development

    Install the required system packages using pacman:

    sudo pacman -S llvm clang lld python python-pip squashfs-tools base-devel git cmake

    Then install the Python dependencies via pip:

    pip install --user -r requirements.txt
    sudo pacman -S llvm clang lld python python-pip squashfs-tools base-devel git cmake
    pip install --user -r requirements.txt
  9. Build libtransistor from source

    development

    To build libtransistor from source, follow these steps:

    1. Clone the repository recursively:
      git clone --recursive https://github.com/reswitched/libtransistor
    2. Obtain libtransistor-base. You can either build it yourself or download a pre-built release. The version of libtransistor-base should match the version of libtransistor you are building (or be the next lowest version).
    3. If building from source, copy the dist/ folder from libtransistor-base to the root of the libtransistor repository. If using a pre-built release, extract it into a folder named dist at the root of the repository.
    4. Ensure you have Python 3 (with dependencies from dist/requirements.txt), clang, and lld >= 5.0 installed.
    5. Run make from the root directory. This will generate nro and nso files in build/test/.
    git clone --recursive https://github.com/reswitched/libtransistor
    # ... setup dist folder ...
    make
  10. Use libtransistor in a Makefile-based build system

    development

    If your project uses a Makefile, you can integrate libtransistor by including $(LIBTRANSISTOR_HOME)/libtransistor.mk.

    Note that you will also need to provide custom linking rules. For a reference implementation, see the projects/example/Makefile in the repository.

    include $(LIBTRANSISTOR_HOME)/libtransistor.mk
  11. Run libtransistor binaries using ctu

    development

    Use the ctu tool to load and run NRO binaries. For the bsd test, you can optionally pass the --enable-sockets flag (use caution as this allows network access).

    ./ctu --load-nro <path-to-libtransistor>/build/test/<binary>.nro
    ./ctu --load-nro <path-to-libtransistor>/build/test/<binary>.nro