diff --git a/.github/workflows/build-extension.yml b/.github/workflows/build-extension.yml new file mode 100644 index 0000000..a29ecd6 --- /dev/null +++ b/.github/workflows/build-extension.yml @@ -0,0 +1,102 @@ +name: Build extension +on: + workflow_call: + inputs: + os: + type: string + required: true + cc: + type: string + required: true + cxx: + type: string + upload: + type: boolean + required: false + default: false + upload-artifact-name: + type: string + required: false + default: package + debug: + type: boolean + required: false + default: false + cache-key: + type: string + required: true + cache-dir: + type: string + required: true + +jobs: + build: + name: Accelerator Extension ${{ inputs.os }}-${{ inputs.cc }} + runs-on: ${{ inputs.os }} + + env: + SOURCEMOD: ${{ github.workspace }}/${{ inputs.cache-dir }}/sourcemod + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + submodules: true + + - name: Retrieve the cache + id: cache + uses: actions/cache@v4 + with: + path: ${{ inputs.cache-dir }} + key: ${{ inputs.cache-key }} + fail-on-cache-miss: true + enableCrossOsArchive: true + + - name: Linux dependencies + if: startsWith(runner.os, 'Linux') + run: | + sudo dpkg --add-architecture i386 + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + gcc-multilib g++-multilib libstdc++6 lib32stdc++6 \ + libc6-dev libc6-dev-i386 linux-libc-dev \ + linux-libc-dev:i386 lib32z1-dev \ + zlib1g-dev:i386 zlib1g-dev ${{ inputs.cc }} + + - name: Select clang compiler + if: startsWith(runner.os, 'Linux') + run: | + echo "CC=${{ inputs.cc }}" >> $GITHUB_ENV + echo "CXX=${{ inputs.cxx }}" >> $GITHUB_ENV + ${{ inputs.cc }} --version + ${{ inputs.cxx }} --version + + - uses: actions/setup-python@v5 + name: Setup Python 3.10 + with: + python-version: '3.10' + + - name: Install AMBuild + run: | + python -m pip install --upgrade pip setuptools wheel + pip install ./${{ inputs.cache-dir }}/ambuild + + - name: Build (Debug) + if: ${{ inputs.debug }} + run: | + mkdir -p build && cd build + python ../configure.py --enable-debug + ambuild + + - name: Build (Release) + if: not ${{ inputs.debug }} + run: | + mkdir -p build && cd build + python ../configure.py --enable-optimize + ambuild + + - name: Upload package + if: ${{ inputs.upload }} + uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.upload-artifact-name }} + path: build/package \ No newline at end of file diff --git a/.github/workflows/cache.yml b/.github/workflows/cache.yml new file mode 100644 index 0000000..0bd3c0f --- /dev/null +++ b/.github/workflows/cache.yml @@ -0,0 +1,57 @@ +name: Cache +on: + workflow_call: + outputs: + key: + value: ${{ jobs.cache.outputs.key }} + dir: + value: .cache + +jobs: + cache: + name: Create cache + runs-on: 'ubuntu-latest' + outputs: + key: ${{ steps.cache-key.outputs.key }} + + env: + SOURCEMOD_REF: 'e0e018c5ebcd11df9bab91b43d40bf148805c684' + AMBUILD_REF: '2d4620da4cdaf89cf25afc3577f920e6138ae7cd' + steps: + - uses: actions/checkout@v4 + + - name: Create cache key + run: | + echo "${{ env.SOURCEMOD_REF }}" >> cache-key + echo "${{ env.AMBUILD_REF }}" >> cache-key + + - name: Output cache key + id: cache-key + run: | + ls -a + echo "key=cache-${{ hashFiles('cache-key') }}" >> $GITHUB_OUTPUT + + - name: Retrieve the cache + id: cache + uses: actions/cache@v4 + with: + path: .cache + key: ${{ steps.cache-key.outputs.key }} + enableCrossOsArchive: true + + - uses: actions/checkout@v4 + if: ${{ !steps.cache.outputs.cache-hit }} + name: SourceMod checkout + with: + repository: alliedmodders/sourcemod + ref: ${{ env.SOURCEMOD_REF }} + submodules: true + path: .cache/sourcemod + + - uses: actions/checkout@v4 + if: ${{ !steps.cache.outputs.cache-hit }} + name: AMBuild checkout + with: + repository: alliedmodders/ambuild + ref: ${{ env.AMBUILD_REF }} + path: .cache/ambuild \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..45d1657 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,56 @@ +name: CI +on: + workflow_dispatch: + pull_request: + branches: + - master + - overhaul + + push: + branches: + - master + - overhaul + +jobs: + cache: + uses: ./.github/workflows/cache.yml + + build: + name: Build + needs: cache + + strategy: + fail-fast: false + matrix: + os: [ 'ubuntu-20.04', 'ubuntu-latest', 'windows-2019', 'windows-latest' ] + include: + - os: ubuntu-20.04 + cc: clang-8 + cxx: clang++-8 + upload: false + upload-artifact-name: none + - os: ubuntu-latest + cc: clang + cxx: clang++ + upload: true + upload-artifact-name: accelerator_linux + - os: windows-2019 + cc: msvc + cxx: msvc + upload: false + upload-artifact-name: none + - os: windows-latest + cc: msvc + cxx: msvc + upload: true + upload-artifact-name: accelerator_windows + + uses: ./.github/workflows/build-extension.yml + with: + os: ${{ matrix.os }} + cc: ${{ matrix.cc }} + cxx: ${{ matrix.cxx }} + upload: ${{ matrix.upload }} + upload-artifact-name: ${{ matrix.upload-artifact-name }} + cache-key: ${{ needs.cache.outputs.key }} + cache-dir: ${{ needs.cache.outputs.dir }} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 0860212..f0d534e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /build /extension/version_auto.h -/breakpad +.vscode \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..830a6ca --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "breakpad"] + path = third_party/breakpad + url = https://github.com/google/breakpad.git +[submodule "zlib"] + path = third_party/zlib + url = https://github.com/madler/zlib.git diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index dd293e2..0000000 --- a/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -sudo: false -language: cpp -addons: - apt: - packages: - - g++-multilib - - libc6-dev:i386 -compiler: - - clang -before_script: - - cd .. - - git clone --depth=1 --branch=1.8-dev --recursive https://github.com/alliedmodders/sourcemod sourcemod-1.8 - - git clone --depth=1 --branch=master --recursive https://github.com/alliedmodders/ambuild - - cd ambuild && python setup.py install --user - - cd $TRAVIS_BUILD_DIR - - git fetch --unshallow || true - - ./breakpad.sh && export PATH=$PATH:$PWD/breakpad/build/src/tools/linux/dump_syms/ -script: - - mkdir build && cd build - - python ../configure.py --enable-optimize - - python ./build.py -after_success: - - python ../upload.py diff --git a/AMBuildScript b/AMBuildScript index e92c894..47c1367 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -1,242 +1,216 @@ -# vim: set ts=2 sw=2 tw=99 noet ft=python: -import os -import sys -from ambuild.command import Command -from ambuild.command import ShellCommand -from ambuild.command import SymlinkCommand +# vim: set ts=2 sw=2 tw=99 noet ft=python: +import os, sys, shutil -class ExtractDebugInfoCommand(Command): - def __init__(self, binary, outfile): - Command.__init__(self) - self.binary = binary - self.outfile = outfile +def ResolveEnvPath(env, folder=None): + if env in os.environ: + path = os.environ[env] + if os.path.isdir(path): + return path + return None - def run(self, runner, job): - if not self.binary.NeedsRelink(self.outfile): - return + if folder: + head = os.getcwd() + oldhead = None + while head != None and head != oldhead: + path = os.path.join(head, folder) + if os.path.isdir(path): + return path + oldhead = head + head, tail = os.path.split(head) - if AMBuild.target['platform'] == 'linux': - job.AddCommand(ShellCommand('objcopy --only-keep-debug ' + self.outfile + ' ' + self.outfile + '.dbg')) - job.AddCommand(ShellCommand('objcopy --strip-debug ' + self.outfile)) - job.AddCommand(ShellCommand('objcopy --add-gnu-debuglink=' + os.path.basename(self.outfile) + '.dbg ' + self.outfile)) - elif AMBuild.target['platform'] == 'darwin': - job.AddCommand(ShellCommand('dsymutil ' + self.outfile)) - job.AddCommand(ShellCommand('strip -S ' + self.outfile)) + return None -class SM: - def __init__(self): - self.compiler = Cpp.Compiler() +def Normalize(path): + return os.path.abspath(os.path.normpath(path)) - if AMBuild.mode == 'config': - #Detect compilers - self.compiler.DetectAll(AMBuild) +class AcceleratorConfig(object): + def __init__(self): + self.mms_root = None + self.sm_root = None + self.extension = None + self.libz = None + self.libbreakpad_client = None + self.libbreakpad = None + self.libdisasm = None + self.breakpad_patch = None + self.targets = [] + self.target_archs = set() + self.breakpad_config = dict() + self.breakpad_patch = None - #Detect variables - envvars = { 'SOURCEMOD': 'sourcemod-1.8' } + if builder.options.targets: + target_archs = builder.options.targets.split(',') + else: + target_archs = ['x86', 'x86_64'] - # Finds if a dict with `key` set to `value` is present on the dict of dicts `dictionary` - def findDictByKey(dictionary, key, value): - for index in dictionary: - elem = dictionary[index] - if elem[key] == value: - return (elem, index) - return None + for arch in target_archs: + try: + cxx = builder.DetectCxx(target_arch = arch) + self.target_archs.add(cxx.target.arch) + except Exception as e: + if builder.options.targets: + raise + print('Skipping target {}: {}'.format(arch, e)) + continue + self.targets.append(cxx) - for i in envvars: - if i in os.environ: - path = os.environ[i] - if not os.path.isdir(path): - raise Exception('Path for {0} was not found: {1}'.format(i, path)) - else: - head = os.getcwd() - oldhead = None - while head != None and head != oldhead: - path = os.path.join(head, envvars[i]) - if os.path.isdir(path): - break - oldhead = head - head, tail = os.path.split(head) - if head == None or head == oldhead: - raise Exception('Could not find a valid path for {0}'.format(i)) - AMBuild.cache.CacheVariable(i, path) + if not self.targets: + raise Exception('No suitable C/C++ compiler was found.') + + @property + def tag(self): + if builder.options.debug == '1': + return 'Debug' + return 'Release' + + def retrieve_sm(self): + if builder.options.sm_path: + self.sm_root = builder.options.sm_path + else: + self.sm_root = ResolveEnvPath('SOURCEMOD', 'sourcemod') - #Set up defines - cxx = self.compiler.cxx - if isinstance(cxx, Cpp.CompatGCC): - if isinstance(cxx, Cpp.GCC): - self.vendor = 'gcc' - elif isinstance(cxx, Cpp.Clang): - self.vendor = 'clang' - self.compiler.AddToListVar('CDEFINES', 'stricmp=strcasecmp') - self.compiler.AddToListVar('CDEFINES', '_stricmp=strcasecmp') - self.compiler.AddToListVar('CDEFINES', '_snprintf=snprintf') - self.compiler.AddToListVar('CDEFINES', '_vsnprintf=vsnprintf') - self.compiler.AddToListVar('CFLAGS', '-pipe') - self.compiler.AddToListVar('CFLAGS', '-fno-strict-aliasing') - if (self.vendor == 'gcc' and cxx.majorVersion >= 4) or self.vendor == 'clang': - self.compiler.AddToListVar('CFLAGS', '-fvisibility=hidden') - self.compiler.AddToListVar('CXXFLAGS', '-fvisibility-inlines-hidden') - self.compiler.AddToListVar('CFLAGS', '-Wall') - self.compiler.AddToListVar('CFLAGS', '-Werror') - self.compiler.AddToListVar('CFLAGS', '-Wno-unused') - self.compiler.AddToListVar('CFLAGS', '-Wno-switch') - self.compiler.AddToListVar('CFLAGS', '-Wno-implicit-exception-spec-mismatch') - self.compiler.AddToListVar('CFLAGS', '-msse') - self.compiler.AddToListVar('CFLAGS', '-g3') - self.compiler.AddToListVar('CFLAGS', '-m32') - self.compiler.AddToListVar('POSTLINKFLAGS', '-m32') - self.compiler.AddToListVar('POSTLINKFLAGS', '-Wl,-z,defs') - self.compiler.AddToListVar('CXXFLAGS', '-std=c++11') - self.compiler.AddToListVar('CXXFLAGS', '-fno-threadsafe-statics') - self.compiler.AddToListVar('CXXFLAGS', '-Wno-non-virtual-dtor') - self.compiler.AddToListVar('CXXFLAGS', '-Wno-overloaded-virtual') - if (self.vendor == 'gcc' and cxx.majorVersion >= 4 and cxx.minorVersion >= 3) or \ - (self.vendor == 'clang' and cxx.majorVersion >= 3): - self.compiler.AddToListVar('CXXFLAGS', '-Wno-delete-non-virtual-dtor') - if self.vendor == 'clang' and cxx.majorVersion >= 3: - self.compiler.AddToListVar('CXXFLAGS', '-Wno-implicit-exception-spec-mismatch') - self.compiler.AddToListVar('CDEFINES', 'HAVE_STDINT_H') - self.compiler.AddToListVar('CDEFINES', 'GNUC') - self.compiler.AddToListVar('CDEFINES', '_GLIBCXX_USE_CXX11_ABI=0') - if self.vendor == 'gcc': - self.compiler.AddToListVar('CFLAGS', '-mfpmath=sse') - elif isinstance(cxx, Cpp.MSVC): - self.vendor = 'msvc' - if AMBuild.options.debug == '1': - self.compiler.AddToListVar('CFLAGS', '/MTd') - self.compiler.AddToListVar('POSTLINKFLAGS', '/NODEFAULTLIB:libcmt') - else: - self.compiler.AddToListVar('CFLAGS', '/MT') - self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_DEPRECATE') - self.compiler.AddToListVar('CDEFINES', '_CRT_SECURE_NO_WARNINGS') - self.compiler.AddToListVar('CDEFINES', '_CRT_NONSTDC_NO_DEPRECATE') - self.compiler.AddToListVar('CXXFLAGS', '/EHsc') - self.compiler.AddToListVar('CFLAGS', '/W3') - self.compiler.AddToListVar('CFLAGS', '/nologo') - self.compiler.AddToListVar('CFLAGS', '/Zi') - self.compiler.AddToListVar('CXXFLAGS', '/TP') - self.compiler.AddToListVar('POSTLINKFLAGS', '/DEBUG') - self.compiler.AddToListVar('POSTLINKFLAGS', '/MACHINE:X86') - self.compiler.AddToListVar('POSTLINKFLAGS', '/SUBSYSTEM:WINDOWS') - self.compiler.AddToListVar('POSTLINKFLAGS', 'kernel32.lib') - self.compiler.AddToListVar('POSTLINKFLAGS', 'user32.lib') - self.compiler.AddToListVar('POSTLINKFLAGS', 'gdi32.lib') - self.compiler.AddToListVar('POSTLINKFLAGS', 'winspool.lib') - self.compiler.AddToListVar('POSTLINKFLAGS', 'comdlg32.lib') - self.compiler.AddToListVar('POSTLINKFLAGS', 'advapi32.lib') - self.compiler.AddToListVar('POSTLINKFLAGS', 'shell32.lib') - self.compiler.AddToListVar('POSTLINKFLAGS', 'ole32.lib') - self.compiler.AddToListVar('POSTLINKFLAGS', 'oleaut32.lib') - self.compiler.AddToListVar('POSTLINKFLAGS', 'uuid.lib') - self.compiler.AddToListVar('POSTLINKFLAGS', 'odbc32.lib') - self.compiler.AddToListVar('POSTLINKFLAGS', 'odbccp32.lib') + if not self.sm_root or not os.path.isdir(self.sm_root): + raise Exception('Could not find a source copy of SourceMod') + self.sm_root = Normalize(self.sm_root) + + def use_auto_versioning(self): + return not builder.options.disable_auto_versioning + + def configure_cxx(self, cxx): + if cxx.like('gcc'): + self.configure_gcc(cxx) + elif cxx.family == 'msvc': + self.configure_msvc(cxx) - #Optimization - if AMBuild.options.opt == '1': - self.compiler.AddToListVar('CDEFINES', 'NDEBUG') - if self.vendor == 'gcc' or self.vendor == 'clang': - self.compiler.AddToListVar('CFLAGS', '-O3') - elif self.vendor == 'msvc': - self.compiler.AddToListVar('CFLAGS', '/Ox') - self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:ICF') - self.compiler.AddToListVar('POSTLINKFLAGS', '/OPT:REF') + # Optimization + if builder.options.opt == '1': + cxx.defines += ['NDEBUG'] - #Debugging - if AMBuild.options.debug == '1': - self.compiler.AddToListVar('CDEFINES', 'DEBUG') - self.compiler.AddToListVar('CDEFINES', '_DEBUG') - if self.vendor == 'msvc': - self.compiler.AddToListVar('CFLAGS', '/Od') - self.compiler.AddToListVar('CFLAGS', '/RTC1') + # Debugging + if builder.options.debug == '1': + cxx.defines += ['DEBUG', '_DEBUG'] - #Platform-specifics - if AMBuild.target['platform'] == 'linux': - self.compiler.AddToListVar('CDEFINES', '_LINUX') - self.compiler.AddToListVar('CDEFINES', 'POSIX') - self.compiler.AddToListVar('CDEFINES', 'NO_MALLOC_OVERRIDE') - if self.vendor == 'gcc': - self.compiler.AddToListVar('POSTLINKFLAGS', '-static-libgcc') - if self.vendor == 'clang': - self.compiler.AddToListVar('POSTLINKFLAGS', '-lgcc_eh') - elif AMBuild.target['platform'] == 'darwin': - self.compiler.AddToListVar('CDEFINES', 'OSX') - self.compiler.AddToListVar('CDEFINES', '_OSX') - self.compiler.AddToListVar('POSTLINKFLAGS', '-mmacosx-version-min=10.5') - self.compiler.AddToListVar('POSTLINKFLAGS', ['-arch', 'i386']) - self.compiler.AddToListVar('POSTLINKFLAGS', '-lstdc++') + # Platform-specifics + if cxx.target.platform == 'linux': + self.configure_linux(cxx) + elif cxx.target.platform == 'windows': + self.configure_windows(cxx) - # For OS X dylib versioning - import re - productFile = open(os.path.join(AMBuild.sourceFolder, 'product.version'), 'r') - productContents = productFile.read() - productFile.close() - m = re.match('(\d+)\.(\d+)\.(\d+).*', productContents) - if m == None: - self.version = '1.0.0' - else: - major, minor, release = m.groups() - self.version = '{0}.{1}.{2}'.format(major, minor, release) - AMBuild.cache.CacheVariable('version', self.version) - elif AMBuild.target['platform'] == 'windows': - self.compiler.AddToListVar('CDEFINES', 'WIN32') - self.compiler.AddToListVar('CDEFINES', '_WINDOWS') + if self.use_auto_versioning(): + cxx.defines += ['GIT_ACTION_BUILD'] + + def configure_gcc(self, cxx): + cxx.cflags += [ + '-fPIC', + '-pipe', + '-fno-strict-aliasing', + '-fvisibility=hidden', + '-fvisibility-inlines-hidden', + '-Wall', + '-Werror', + '-msse' + ] - #Finish up - self.compiler.AddToListVar('CDEFINES', 'SOURCEMOD_BUILD') - self.compiler.AddToListVar('CDEFINES', 'SM_GENERATED_BUILD') - self.compiler.AddToListVar('CINCLUDES', - os.path.join(AMBuild.outputFolder, 'includes')) - self.compiler.ToConfig(AMBuild, 'compiler') - AMBuild.cache.CacheVariable('vendor', self.vendor) - self.targetMap = { } - AMBuild.cache.CacheVariable('targetMap', self.targetMap) - else: - self.compiler.FromConfig(AMBuild, 'compiler') - self.targetMap = AMBuild.cache['targetMap'] + cxx.cxxflags += [ + '-std=c++17', + '-fno-threadsafe-statics', + '-Wno-non-virtual-dtor', + '-Wno-overloaded-virtual', + '-Wno-implicit-exception-spec-mismatch' + ] - if AMBuild.target['platform'] == 'windows': - self.compiler.AddToListVar('RCINCLUDES', os.path.join(AMBuild.sourceFolder, 'extension')) + cxx.postlink += ['-pthread', '-static-libstdc++', '-static-libgcc'] - def DefaultCompiler(self): - return self.compiler.Clone() + if builder.options.opt == '1': + cxx.cflags += ['-O3'] + return - def JobMatters(self, jobname): - file = sys._getframe().f_code.co_filename - if AMBuild.mode == 'config': - self.targetMap[jobname] = file - return True - if len(AMBuild.args) == 0: - return True - if not jobname in AMBuild.args: - return False + def configure_msvc(self, cxx): - def AutoVersion(self, folder, binary): - if AMBuild.target['platform'] == 'windows': - env = {'RCDEFINES': ['BINARY_NAME="' + binary.binaryFile + '"', 'SM_GENERATED_BUILD']} - binary.AddResourceFile(os.path.join(folder, 'version.rc' ), env) - elif AMBuild.target['platform'] == 'darwin' and isinstance(binary, Cpp.LibraryBuilder): - binary.compiler['POSTLINKFLAGS'].extend(['-compatibility_version', '1.0.0']) - binary.compiler['POSTLINKFLAGS'].extend(['-current_version', AMBuild.cache['version']]) - else: - return + cxx.cxxflags += [ + '/EHsc', + '/std:c++17' + ] - def ExtractDebugInfo(self, job, binary): - src = os.path.join('..', AMBuild.outputFolder, job.workFolder, binary.binaryFile) - job.AddCommand(ExtractDebugInfoCommand(binary, src)) + return + + def configure_linux(self, cxx): + cxx.defines += ['_LINUX', 'POSIX', '_GLIBCXX_USE_CXX11_ABI=0'] + return + + def configure_windows(self, cxx): + cxx.defines += ['_WINDOWS'] + if cxx.target.arch == 'x86': + cxx.defines += ['WIN32'] + elif cxx.target.arch == 'x86_64': + cxx.defines += ['WIN64'] + return + + def configure(self): + self.retrieve_sm() -sm = SM() -globals = { - 'SM': sm -} + for cxx in self.targets: + self.configure_cxx(cxx) -AMBuild.Include(os.path.join('buildbot', 'Versioning'), globals) + def configure_extension(self, compiler, context): + compiler.cxxincludes += [ + os.path.join(context.currentSourcePath), + os.path.join(self.sm_root, 'public'), + os.path.join(self.sm_root, 'public', 'extensions'), + os.path.join(self.sm_root, 'public', 'amtl', 'amtl'), + os.path.join(self.sm_root, 'public', 'amtl'), + os.path.join(self.sm_root, 'sourcepawn', 'include') + ] -FileList = [ - ['extension', 'AMBuilder'], - ['test', 'AMBuilder'], - ['buildbot', 'PackageScript'], - ['buildbot', 'BreakpadSymbols'] - ] + def link_libz(self, compiler, context): + for task in self.libz: + if task.target.arch == compiler.target.arch: + compiler.postlink += [os.path.join(context.buildPath, task.binary.path)] + compiler.linkdeps += [task.binary] + return + raise Exception('No suitable build of libz was found.') + + def link_libbreakpad_client(self, compiler, context): + for task in self.libbreakpad_client: + if task.target.arch == compiler.target.arch: + compiler.postlink += [os.path.join(context.buildPath, task.binary.path)] + compiler.linkdeps += [task.binary] + return + raise Exception('No suitable build of libbreakpad_client was found.') + + def link_libbreakpad(self, compiler, context): + for task in self.libbreakpad: + if task.target.arch == compiler.target.arch: + compiler.postlink += [os.path.join(context.buildPath, task.binary.path)] + compiler.linkdeps += [task.binary] + return + raise Exception('No suitable build of libbreakpad was found.') + + def link_libdisasm(self, compiler, context): + for task in self.libdisasm: + if task.target.arch == compiler.target.arch: + compiler.postlink += [os.path.join(context.buildPath, task.binary.path)] + compiler.linkdeps += [task.binary] + return + raise Exception('No suitable build of libdisasm was found.') + + def ConfigureLibrary(self, project, compiler, context): + binary = project.Configure(compiler, project.name, '{0} - {1}'.format(self.tag, compiler.target.arch)) + binary.compiler.cxxincludes += [ + os.path.join(context.currentSourcePath) + ] + return binary + + def ConfigureExtension(self, project, compiler, context): + binary = self.ConfigureLibrary(project, compiler, context) + self.configure_extension(binary.compiler, context) + return binary + +Accelerator = AcceleratorConfig() +Accelerator.configure() + +builder.Build(['third_party/Patch', 'third_party/Configure', 'third_party/AMBuilder'], { 'Accelerator': Accelerator }) + +BuildScripts = ['extension/AMBuilder', 'buildbot/PackageScript'] +builder.Build(BuildScripts, { 'Accelerator': Accelerator }) -for parts in FileList: - AMBuild.Include(os.path.join(*parts), globals) diff --git a/README.md b/README.md new file mode 100644 index 0000000..e6779f8 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Accelerator diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 690eba4..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,24 +0,0 @@ -version: '{build}' -os: Visual Studio 2015 -environment: - GYP_MSVS_VERSION: '2015' -install: - - cd .. - - git clone --depth=1 --branch=1.8-dev --recursive https://github.com/alliedmodders/sourcemod sourcemod-1.8 - - git clone --depth=1 --branch=master https://github.com/alliedmodders/ambuild - - cd ambuild - - C:\python27\python.exe setup.py install - - cd %APPVEYOR_BUILD_FOLDER% - - '"%VS140COMNTOOLS%\vsvars32.bat"' - - breakpad.bat - - set PATH=%PATH%;%CD%\breakpad\src\src\tools\windows\dump_syms\Release -build_script: - - mkdir build - - cd build - - C:\python27\python.exe ..\configure.py --enable-optimize - - C:\python27\python.exe build.py -test: off -on_success: - - C:\python27\python.exe ..\upload.py -#on_finish: -# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) diff --git a/breakpad.bat b/breakpad.bat deleted file mode 100644 index 9143564..0000000 --- a/breakpad.bat +++ /dev/null @@ -1,70 +0,0 @@ -@echo on - -IF EXIST C:\Python27\NUL SET PATH=C:\Python27\;%PATH% - -python --version -@IF %errorlevel% neq 0 EXIT /b %errorlevel% - -@IF EXIST breakpad\NUL GOTO HASBREAKPAD -mkdir breakpad -:HASBREAKPAD -cd breakpad - -@IF EXIST depot_tools\NUL GOTO HASDEPOTTOOLS -git clone --depth=1 --branch=master https://chromium.googlesource.com/chromium/tools/depot_tools.git depot_tools -@IF %errorlevel% neq 0 EXIT /b %errorlevel% -:HASDEPOTTOOLS - -@IF EXIST src\NUL GOTO HASSRC -cmd /c depot_tools\fetch --nohooks breakpad -@IF %errorlevel% neq 0 EXIT /b %errorlevel% -GOTO DONESRC -:HASSRC -git -C src fetch -git -C src reset --hard origin/master -@IF %errorlevel% neq 0 EXIT /b %errorlevel% -cmd /c depot_tools\gclient sync --nohooks -@IF %errorlevel% neq 0 EXIT /b %errorlevel% -:DONESRC - -cd src -git config user.name patches -git config user.email patches@localhost -powershell -Command "& {git am -3 --keep-cr $(ls ..\..\patches\*.patch | %% {$_.FullName})}" -@IF %errorlevel% neq 0 EXIT /b %errorlevel% -cd .. - -@IF EXIST gyp\NUL GOTO HASGYP -git clone --depth=1 --branch=master https://chromium.googlesource.com/external/gyp.git gyp -@IF %errorlevel% neq 0 EXIT /b %errorlevel% -:HASGYP - -powershell -Command "& {(Get-Content src\src\build\common.gypi).replace('''WarnAsError'': ''true'',', '''WarnAsError'': ''false'',') | Set-Content src\src\build\common.gypi}" -@IF %errorlevel% neq 0 EXIT /b %errorlevel% - -cmd /c gyp\gyp.bat --no-circular-check src\src\client\windows\handler\exception_handler.gyp -@IF %errorlevel% neq 0 EXIT /b %errorlevel% -msbuild src\src\client\windows\handler\exception_handler.sln /m /p:Configuration=Release /p:Platform=Win32 -@IF %errorlevel% neq 0 EXIT /b %errorlevel% - -cmd /c gyp\gyp.bat --no-circular-check src\src\client\windows\crash_generation\crash_generation.gyp -@IF %errorlevel% neq 0 EXIT /b %errorlevel% -msbuild src\src\client\windows\crash_generation\crash_generation.sln /m /p:Configuration=Release /p:Platform=Win32 -@IF %errorlevel% neq 0 EXIT /b %errorlevel% - -cmd /c gyp\gyp.bat --no-circular-check src\src\processor\processor.gyp -IF %errorlevel% neq 0 EXIT /b %errorlevel% -@REM msbuild src\src\processor\processor.sln /m /p:Configuration=Release /p:Platform=Win32 -@REM IF %errorlevel% neq 0 EXIT /b %errorlevel% -@REM The solution file is currently including a load of broken projects, so just build exactly what we need. -msbuild src\src\processor\processor.vcxproj /m /p:Configuration=Release /p:Platform=Win32 -@IF %errorlevel% neq 0 EXIT /b %errorlevel% -msbuild src\src\third_party\libdisasm\libdisasm.vcxproj /m /p:Configuration=Release /p:Platform=Win32 -@IF %errorlevel% neq 0 EXIT /b %errorlevel% - -cmd /c gyp\gyp.bat --no-circular-check src\src\tools\windows\dump_syms\dump_syms.gyp -@IF %errorlevel% neq 0 EXIT /b %errorlevel% -msbuild src\src\tools\windows\dump_syms\dump_syms.sln /m /p:Configuration=Release /p:Platform=Win32 -@IF %errorlevel% neq 0 EXIT /b %errorlevel% - -cd .. diff --git a/breakpad.sh b/breakpad.sh deleted file mode 100755 index 31df9b2..0000000 --- a/breakpad.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -set -ex - -if [ ! -d "breakpad" ]; then - mkdir breakpad -fi - -cd breakpad - -if [ ! -d "depot_tools" ]; then - git clone --depth=1 --branch=master https://chromium.googlesource.com/chromium/tools/depot_tools.git depot_tools -fi - -if [ ! -d "src" ]; then - PYTHONDONTWRITEBYTECODE=1 python2.7 ./depot_tools/fetch.py --nohooks breakpad -else - git -C src fetch - git -C src reset --hard origin/master - PYTHONDONTWRITEBYTECODE=1 python2.7 ./depot_tools/gclient.py sync --nohooks -fi - -cd src -git config user.name patches -git config user.email patches@localhost -git am -3 --keep-cr ../../patches/*.patch -cd .. - -if [ ! -d "build" ]; then - mkdir build -fi - -cd build - -../src/configure --enable-m32 CXXFLAGS="-g -O2 -D_GLIBCXX_USE_CXX11_ABI=0" - -make src/tools/linux/dump_syms/dump_syms -make src/client/linux/libbreakpad_client.a -make src/libbreakpad.a src/third_party/libdisasm/libdisasm.a diff --git a/buildbot/PackageScript b/buildbot/PackageScript index ab241b3..8b428e3 100644 --- a/buildbot/PackageScript +++ b/buildbot/PackageScript @@ -1,127 +1,53 @@ -# vim: set ts=2 sw=2 tw=99 noet ft=python: +# vim: set ts=8 sts=2 sw=2 tw=99 et ft=python: import os -import shutil -import ambuild.osutil as osutil -from ambuild.command import Command -job = AMBuild.AddJob('package') +# This is where the files will be output to +# package is the default +builder.SetBuildFolder('package') -class DestroyPath(Command): - def __init__(self, folder): - Command.__init__(self) - self.folder = folder - - def destroy(self, path): - entries = os.listdir(path) - for entry in entries: - newpath = os.path.join(path, entry) - if os.path.isdir(newpath): - self.destroy(newpath) - os.rmdir(newpath) - elif os.path.isfile(newpath): - os.remove(newpath) - - def run(self, runner, job): - runner.PrintOut('rm -rf {0}/*'.format(self.folder)) - self.destroy(self.folder) - -class CreateFolders(Command): - def __init__(self, folders): - Command.__init__(self) - self.folders = folders - - def run(self, runner, job): - for folder in self.folders: - path = os.path.join(*folder) - runner.PrintOut('mkdir {0}'.format(path)) - os.makedirs(path) - -#Shallow folder copy -class CopyFolder(Command): - def __init__(self, fromList, toList, excludes = []): - Command.__init__(self) - self.fromPath = os.path.join(AMBuild.sourceFolder, *fromList) - self.toPath = os.path.join(*toList) - self.excludes = excludes - - def run(self, runner, job): - entries = os.listdir(self.fromPath) - for entry in entries: - if entry in self.excludes: - continue - path = os.path.join(self.fromPath, entry) - if not os.path.isfile(path): - continue - runner.PrintOut('copy {0} to {1}'.format(path, self.toPath)) - shutil.copy(path, self.toPath) - -#Single file copy -class CopyFile(Command): - def __init__(self, fromFile, toPath): - Command.__init__(self) - self.fromFile = fromFile - self.toPath = toPath - - def run(self, runner, job): - runner.PrintOut('copy {0} to {1}'.format(self.fromFile, self.toPath)) - shutil.copy(self.fromFile, self.toPath) - - -folders = [ - ['addons', 'sourcemod', 'configs'], - ['addons', 'sourcemod', 'gamedata'], - ['addons', 'sourcemod', 'extensions'], +# Add any folders you need to this list +folder_list = [ + 'addons/sourcemod/extensions', + 'addons/sourcemod/gamedata', + 'addons/sourcemod/configs' ] -#Setup -job.AddCommand(DestroyPath(os.path.join(AMBuild.outputFolder, 'package'))) -job.AddCommand(CreateFolders(folders)) +# Are we build a x86_64 extension ? +for task in Accelerator.extension: + if task.target.arch == 'x86_64': + folder_list += ['addons/sourcemod/extensions/x64'] + break -job.AddCommand(CopyFile(os.path.join(AMBuild.sourceFolder, 'accelerator.games.txt'), os.path.join('addons', 'sourcemod', 'gamedata'))) -job.AddCommand(CopyFile(os.path.join(AMBuild.sourceFolder, 'accelerator.autoload'), os.path.join('addons', 'sourcemod', 'extensions'))) +# Create the distribution folder hierarchy. +folder_map = {} +for folder in folder_list: + norm_folder = os.path.normpath(folder) + folder_map[folder] = builder.AddFolder(norm_folder) -bincopies = [] +# Do all straight-up file copies from the source tree. +def CopyFiles(src, dest, files): + if not dest: + dest = src + dest_entry = folder_map[dest] + for source_file in files: + source_path = os.path.join(builder.sourcePath, src, source_file) + builder.AddCopy(source_path, dest_entry) +def CopyFile(src, dest): + dest_entry = folder_map[dest] + source_path = os.path.join(builder.sourcePath, src) + builder.AddCopy(source_path, dest_entry) +def CopyDirContent(src, dest): + dest_entry = folder_map[dest] + for item in os.scandir(os.path.join(builder.sourcePath, src)): + if item.is_file(): + builder.AddCopy(item.path, dest_entry) -def AddNormalLibrary(name, dest): - dest = os.path.join('addons', 'sourcemod', dest) - bincopies.append(CopyFile(os.path.join('..', name, name + osutil.SharedLibSuffix()), dest)) - - # Each platform's version of dump_syms needs the path in a different format. - if AMBuild.target['platform'] == 'linux': - debug_info.append(name + '/' + name + '.so') - elif AMBuild.target['platform'] == 'darwin': - debug_info.append(name + '/' + name + '.dylib.dSYM') - elif AMBuild.target['platform'] == 'windows': - debug_info.append(name + '\\' + name + '.pdb') - -def AddExecutable(name, dest): - dest = os.path.join('addons', 'sourcemod', dest) - bincopies.append(CopyFile(os.path.join('..', name, name + osutil.ExecutableSuffix()), dest)) - - # Each platform's version of dump_syms needs the path in a different format. - if AMBuild.target['platform'] == 'linux': - debug_info.append(name + '/' + name) - elif AMBuild.target['platform'] == 'darwin': - debug_info.append(name + '/' + name + '.dSYM') - elif AMBuild.target['platform'] == 'windows': - debug_info.append(name + '\\' + name + '.pdb') - -def AddHL2Library(name, dest): - for i in SM.sdkInfo: - sdk = SM.sdkInfo[i] - if AMBuild.target['platform'] not in sdk['platform']: - continue - AddNormalLibrary(name + '.ext.' + sdk['ext'], dest) - -debug_info = [] - -AddNormalLibrary('accelerator.ext', 'extensions') -AddExecutable('test-crash-dump-generation', 'configs') - -job.AddCommandGroup(bincopies) - -pdblog = open(os.path.join(AMBuild.outputFolder, 'pdblog.txt'), 'wt') -for pdb in debug_info: - pdblog.write(pdb + '\n') -pdblog.close() +# Copy binaries. +for task in Accelerator.extension: + if task.target.arch == 'x86_64': + builder.AddCopy(task.binary, folder_map['addons/sourcemod/extensions/x64']) + else: + builder.AddCopy(task.binary, folder_map['addons/sourcemod/extensions']) +CopyDirContent('gamedata', 'addons/sourcemod/gamedata') +CopyFile('extension/accelerator.autoload', 'addons/sourcemod/extensions') \ No newline at end of file diff --git a/configure.py b/configure.py index f0f2aa0..7336cc1 100644 --- a/configure.py +++ b/configure.py @@ -1,10 +1,15 @@ -# vim: set ts=2 sw=2 tw=99 noet: import sys -import ambuild.runner as runner +from ambuild2 import run -run = runner.Runner() -run.options.add_option('--enable-debug', action='store_const', const='1', dest='debug', - help='Enable debugging symbols') -run.options.add_option('--enable-optimize', action='store_const', const='1', dest='opt', - help='Enable optimization') -run.Configure(sys.path[0]) +parser = run.BuildParser(sourcePath = sys.path[0], api='2.2') +parser.options.add_argument('--sm-path', type=str, dest='sm_path', default=None, + help='Path to SourceMod') +parser.options.add_argument('--enable-debug', action='store_const', const='1', dest='debug', + help='Enable debugging symbols') +parser.options.add_argument('--enable-optimize', action='store_const', const='1', dest='opt', + help='Enable optimization') +parser.options.add_argument('--disable-auto-versioning', action='store_false', dest='disable_auto_versioning', + default=True, help='Disables the auto versioning script') +parser.options.add_argument('--targets', type=str, dest='targets', default=None, + help="Override the target architecture (use commas to separate multiple targets).") +parser.Configure() \ No newline at end of file diff --git a/dockerbuild/.gitkeep b/dockerbuild/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/dockerbuild/.gitkeep @@ -0,0 +1 @@ + diff --git a/dockerbuild/_accelerator_docker_build_internal.sh b/dockerbuild/_accelerator_docker_build_internal.sh new file mode 100644 index 0000000..97e43fd --- /dev/null +++ b/dockerbuild/_accelerator_docker_build_internal.sh @@ -0,0 +1,95 @@ +#!/bin/bash + +set -euxo pipefail + + +bootstrapEnv() +{ + # for squashing git whining when people run with docker instead of rootless podman + git config --global --add safe.directory / + git config --global --add safe.directory "*" + + # for preventing any submodule tomfuckery + git submodule update --init --recursive -f + + # whack build dir it's literally faster and easier to do this than to cache it + rm -rfv ./build + + # clean up patch cruft in breakpad dir so we start from a clean slate no matter what + pushd third_party/breakpad + git reset --hard + git clean -x -f -d + git clean -X -f -d + popd +} + + +bootstrapPkgs() +{ + # we really need to slim this shit down lol + dpkg --add-architecture i386 && \ + apt-get update -y && \ + apt-get install -y \ + --no-install-recommends \ + git \ + clang \ + make \ + python3-httplib2 python3-pip \ + lib32stdc++-10-dev lib32z1-dev libc6-dev-i386 linux-libc-dev:i386 \ + libzstd-dev libzstd-dev:i386 zlib1g-dev zlib1g-dev:i386 + + # force clang to be our compiler no matter what, hopefully + update-alternatives --install /usr/bin/cc cc /usr/bin/clang 100 + update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 100 + + # this is just for logging + cc --version || true + c++ --version || true +} + + +smBranch="master" +amTempLocation="_am_temp" +succCloneLocation="/accelerator/${amTempLocation}/successful_clone" +bootstrapAM() +{ + # need to install ambuild if we already cloned, otherwise checkout-deps will do it 4 us + if test -f "${succCloneLocation}"; then + pip install /accelerator/"${amTempLocation}"/ambuild + return 255; + fi + + rm -rf /accelerator/"${amTempLocation}"/ || true + mkdir -p ${amTempLocation} || exit 1 + pushd ${amTempLocation} || exit 1 + git clone -b ${smBranch} --recursive --depth 1 https://github.com/alliedmodders/sourcemod sourcemod || exit 1 + git clone --recursive --depth 1 https://github.com/alliedmodders/ambuild ambuild || exit 1 + pip install ./ambuild + + # make a blank file so that we don't reclone everything if we don't need to + true > "${succCloneLocation}" || exit 1 + popd +} + + +buildIt() +{ + if test ! -d build; then + mkdir -p build + fi + + pushd build + CC=clang CXX=clang++ python3 ../configure.py --sm-path=/accelerator/${amTempLocation}/sourcemod/ + ambuild + popd +} + +############################### + +cd /accelerator + +bootstrapPkgs +bootstrapEnv +bootstrapAM || true + +buildIt diff --git a/dockerbuild/_github_actions_setup.sh b/dockerbuild/_github_actions_setup.sh new file mode 100644 index 0000000..0d4c0ec --- /dev/null +++ b/dockerbuild/_github_actions_setup.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -euxo pipefail + +pwd +ls -la + +mkdir /accelerator +cp -av "$(pwd)"/. /accelerator +cd /accelerator + +pwd +ls -la + + +bash ./dockerbuild/_accelerator_docker_build_internal.sh diff --git a/dockerbuild/accelerator_docker_build.sh b/dockerbuild/accelerator_docker_build.sh new file mode 100644 index 0000000..aae7cd5 --- /dev/null +++ b/dockerbuild/accelerator_docker_build.sh @@ -0,0 +1,49 @@ +#!/bin/bash +set -euxo pipefail + +dockerimage="debian:11-slim" + + +# we do this so that we can be agnostic about where we're invoked from +# meaning you can exec this script anywhere and it should work the same +thisiswhereiam=${BASH_SOURCE[0]} +# this should be /whatever/directory/structure/Open-Fortress-Source +script_folder=$( cd -- "$( dirname -- "${thisiswhereiam}" )" &> /dev/null && pwd ) + + +# this should be /whatever/directory/structure/[accelerator_root]/cicd +build_dir="dockerbuild" + +pushd "${script_folder}" &> /dev/null || exit 99 + + # this is relative to our source dir/build + internalscript="_accelerator_docker_build_internal.sh" + + # this should always be our accelerator root dir + pushd ../ &> /dev/null + dev_srcdir=$(pwd) + container_rootdir="accelerator" + + # add -it flags automatically if in null tty + itflag="" + if [ -t 0 ] ; then + itflag="-it" + else + itflag="" + fi + + podman run ${itflag} \ + -v "${dev_srcdir}":/"${container_rootdir}" \ + -w /${container_rootdir} \ + ${dockerimage} \ + bash ./${build_dir}/${internalscript} "$@" + + ecodereal=$? + echo "real exit code ${ecodereal}" + + popd &> /dev/null || exit + +popd &> /dev/null || exit + +exit ${ecodereal} + diff --git a/extension/AMBuilder b/extension/AMBuilder index bca0acb..1e6f25f 100644 --- a/extension/AMBuilder +++ b/extension/AMBuilder @@ -1,96 +1,58 @@ # vim: set ts=2 sw=2 tw=99 noet ft=python: -import os -import ambuild.osutil as osutil -from ambuild.command import SymlinkCommand -from ambuild.command import ShellCommand -from ambuild.command import DirectCommand +import os, sys -def BuildEverything(): - if AMBuild.target['platform'] not in ['linux', 'windows']: - return +builder.SetBuildFolder('/') - compiler = SM.DefaultCompiler() +project = builder.LibraryProject('accelerator.ext') +project.sources = [ + 'extension.cpp', + 'MemoryDownloader.cpp', + os.path.join(Accelerator.sm_root, 'public', 'smsdk_ext.cpp') +] - compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'extension')) +def AddSourceFilesFromDir(path, files): + list = [] + for file in files: + list.append(os.path.join(path, file)) + return list - compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache['SOURCEMOD'], 'public')) - compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache['SOURCEMOD'], 'public', 'extensions')) - compiler['CXXINCLUDES'].append(os.path.join(AMBuild.cache['SOURCEMOD'], 'sourcepawn', 'include')) +for cxx in Accelerator.targets: + binary = Accelerator.ConfigureExtension(project, cxx, builder) + compiler = binary.compiler + # Wait for breakpad to be patched + compiler.sourcedeps += Accelerator.breakpad_patch + # We depend on breakpad on config + compiler.sourcedeps += Accelerator.breakpad_config[compiler.target.arch] - if AMBuild.target['platform'] in ['linux']: - compiler['POSTLINKFLAGS'].append('-lm') - compiler['POSTLINKFLAGS'].append('-lstdc++') - compiler['POSTLINKFLAGS'].append('-pthread') + compiler.defines += ['HAVE_CONFIG_H'] + compiler.cxxincludes += [ + os.path.join(builder.sourcePath, 'third_party', 'breakpad', 'src'), + os.path.join(builder.buildPath, 'third_party', 'config', compiler.target.arch), + ] - compiler['CDEFINES'].append('HAVE_CONFIG_H') - compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'breakpad', 'build', 'src')) - - compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src')) - - name = 'accelerator.ext' - extension = AMBuild.AddJob(name) - binary = Cpp.LibraryBuilder(name, AMBuild, extension, compiler) - - binary.AddSourceFiles('extension', [ - 'extension.cpp', - 'MemoryDownloader.cpp', - ]) - - binary.AddSourceFiles(AMBuild.cache['SOURCEMOD'], ['public/smsdk_ext.cpp']) - - if AMBuild.target['platform'] in ['linux']: - binary.AddSourceFiles(os.path.join('breakpad', 'src', 'src', 'common'), [ - 'dwarf_cfi_to_module.cc', - 'dwarf_cu_to_module.cc', - 'dwarf_line_to_module.cc', - 'dwarf_range_list_handler.cc', - 'language.cc', - 'module.cc', - 'path_helper.cc', - 'stabs_reader.cc', - 'stabs_to_module.cc', - 'dwarf/bytereader.cc', - 'dwarf/dwarf2diehandler.cc', - 'dwarf/dwarf2reader.cc', - 'dwarf/elf_reader.cc', - 'linux/crc32.cc', - 'linux/dump_symbols.cc', - 'linux/elf_symbols_to_module.cc', + if compiler.target.platform in ['linux']: + binary.sources += AddSourceFilesFromDir(os.path.join(builder.currentSourcePath, '..', 'third_party', 'breakpad', 'src', 'common'), [ + 'dwarf_cfi_to_module.cc', + 'dwarf_cu_to_module.cc', + 'dwarf_line_to_module.cc', + 'dwarf_range_list_handler.cc', + 'language.cc', + 'module.cc', + 'path_helper.cc', + 'stabs_reader.cc', + 'stabs_to_module.cc', + 'dwarf/bytereader.cc', + 'dwarf/dwarf2diehandler.cc', + 'dwarf/dwarf2reader.cc', + 'dwarf/elf_reader.cc', + 'linux/crc32.cc', + 'linux/dump_symbols.cc', + 'linux/elf_symbols_to_module.cc', + 'linux/breakpad_getcontext.S' ]) - if AMBuild.target['platform'] in ['linux']: - libs = [ - ('libbreakpad_client.a', os.path.join('breakpad', 'build', 'src', 'client', 'linux', 'libbreakpad_client.a')), - ('libbreakpad.a', os.path.join('breakpad', 'build', 'src', 'libbreakpad.a')), - ('libdisasm.a', os.path.join('breakpad', 'build', 'src', 'third_party', 'libdisasm', 'libdisasm.a')), - ] + Accelerator.link_libbreakpad_client(compiler, builder) + Accelerator.link_libbreakpad(compiler, builder) + Accelerator.link_libdisasm(compiler, builder) - for lib, target in libs: - link = os.path.join(AMBuild.outputFolder, extension.workFolder, lib) - target = os.path.join(AMBuild.sourceFolder, target) - try: - os.lstat(link) - except: - extension.AddCommand(SymlinkCommand(link, target)) - binary.AddObjectFiles([lib]) - - elif AMBuild.target['platform'] in ['windows']: - libs = [ - os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src', 'client', 'windows', 'handler', 'Release', 'lib', 'common.lib'), - os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src', 'client', 'windows', 'handler', 'Release', 'lib', 'exception_handler.lib'), - os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src', 'client', 'windows', 'crash_generation', 'Release', 'lib', 'crash_generation_client.lib'), - os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src', 'third_party', 'libdisasm', 'Release', 'lib', 'libdisasm.lib'), - os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src', 'processor', 'Release', 'lib', 'processor.lib'), - ] - - for path in libs: - if os.path.isfile(path): - binary.RelinkIfNewer(path) - binary['POSTLINKFLAGS'].extend([path]) - - SM.AutoVersion('extension', binary) - SM.ExtractDebugInfo(extension, binary) - - binary.SendToJob() - -BuildEverything() +Accelerator.extension = builder.Add(project) \ No newline at end of file diff --git a/accelerator.autoload b/extension/accelerator.autoload similarity index 100% rename from accelerator.autoload rename to extension/accelerator.autoload diff --git a/extension/extension.cpp b/extension/extension.cpp index f46ea62..fbd773e 100644 --- a/extension/extension.cpp +++ b/extension/extension.cpp @@ -115,10 +115,10 @@ SMEXT_LINK(&g_accelerator); IWebternet *webternet; IGameConfig *gameconfig; -typedef void (*GetSpew_t)(char *buffer, unsigned int length); +typedef void (*GetSpew_t)(char *buffer, size_t length); GetSpew_t GetSpew; #if defined _WINDOWS -typedef void(__fastcall *GetSpewFastcall_t)(char *buffer, unsigned int length); +typedef void(__fastcall *GetSpewFastcall_t)(char *buffer, size_t length); GetSpewFastcall_t GetSpewFastcall; #endif @@ -504,10 +504,13 @@ class UploadThread: public IThread #if defined _LINUX bool UploadSymbolFile(const google_breakpad::CodeModule *module, const char *presubmitToken) { + if (log) fprintf(log, "UploadSymbolFile\n"); + if (log) fflush(log); + auto debugFile = module->debug_file(); std::string vdsoOutputPath = ""; - if (debugFile == "linux-gate.so") { + if (false && debugFile == "linux-gate.so") { FILE *auxvFile = fopen("/proc/self/auxv", "rb"); if (auxvFile) { char vdsoOutputPathBuffer[512]; @@ -523,7 +526,11 @@ class UploadThread: public IThread if (auxvEntryId == 0) break; if (auxvEntryId != 33) continue; // AT_SYSINFO_EHDR +#ifdef PLATFORM_X64 + Elf64_Ehdr *vdsoHdr = (Elf64_Ehdr *)auxvEntryValue; +#else Elf32_Ehdr *vdsoHdr = (Elf32_Ehdr *)auxvEntryValue; +#endif auto vdsoSize = vdsoHdr->e_shoff + (vdsoHdr->e_shentsize * vdsoHdr->e_shnum); void *vdsoBuffer = malloc(vdsoSize); memcpy(vdsoBuffer, vdsoHdr, vdsoSize); @@ -548,6 +555,7 @@ class UploadThread: public IThread } if (log) fprintf(log, "Submitting symbols for %s\n", debugFile.c_str()); + if (log) fflush(log); auto debugFileDir = google_breakpad::DirName(debugFile); std::vector debug_dirs{ @@ -557,18 +565,19 @@ class UploadThread: public IThread }; std::ostringstream outputStream; - google_breakpad::DumpOptions options(ALL_SYMBOL_DATA, true); + google_breakpad::DumpOptions options(ALL_SYMBOL_DATA, true, true); { StderrInhibitor stdrrInhibitor; - if (!WriteSymbolFile(debugFile, debug_dirs, options, outputStream)) { + if (!WriteSymbolFile(debugFile, debugFile, "Linux", debug_dirs, options, outputStream)) { outputStream.str(""); outputStream.clear(); // Try again without debug dirs. - if (!WriteSymbolFile(debugFile, {}, options, outputStream)) { + if (!WriteSymbolFile(debugFile, debugFile, "Linux", {}, options, outputStream)) { if (log) fprintf(log, "Failed to process symbol file\n"); + if (log) fflush(log); return false; } } @@ -607,6 +616,7 @@ class UploadThread: public IThread if (!symbolUploaded) { if (log) fprintf(log, "Symbol upload failed: %s (%d)\n", xfer->LastErrorMessage(), xfer->LastErrorCode()); + if (log) fflush(log); return false; } @@ -619,7 +629,7 @@ class UploadThread: public IThread } if (log) fprintf(log, "Symbol upload complete: %s\n", response); delete[] response; - + if (log) fflush(log); return true; } #endif @@ -636,6 +646,7 @@ class UploadThread: public IThread } if (log) fprintf(log, "Submitting binary for %s\n", codeFile.c_str()); + if (log) fflush(log); IWebForm *form = webternet->CreateForm(); @@ -665,6 +676,7 @@ class UploadThread: public IThread if (!binaryUploaded) { if (log) fprintf(log, "Binary upload failed: %s (%d)\n", xfer->LastErrorMessage(), xfer->LastErrorCode()); + if (log) fflush(log); return false; } @@ -676,6 +688,7 @@ class UploadThread: public IThread response[--responseSize] = '\0'; } if (log) fprintf(log, "Binary upload complete: %s\n", response); + if (log) fflush(log); delete[] response; return true; @@ -971,12 +984,14 @@ class UploadThread: public IThread if (!submitSymbols && !submitBinary) { continue; } + if (log) fprintf(log, "Getting module at index %d\n", moduleIndex); + if (log) fflush(log); auto module = processState.modules()->GetModuleAtIndex(moduleIndex); auto moduleType = ClassifyModule(module); if (log) fprintf(log, "Classified module %s as %s\n", module->code_file().c_str(), ModuleTypeCode[moduleType]); - + if (log) fflush(log); switch (moduleType) { case kMTUnknown: continue; @@ -1009,6 +1024,8 @@ class UploadThread: public IThread #endif } } + if (log) fprintf(log, "PresubmitCrashDump complete\n"); + if (log) fflush(log); delete[] response; return presubmitResponse; diff --git a/extension/smsdk_config.h b/extension/smsdk_config.h index dace891..7d7c58e 100644 --- a/extension/smsdk_config.h +++ b/extension/smsdk_config.h @@ -40,7 +40,7 @@ #define SMEXT_CONF_NAME "Accelerator" #define SMEXT_CONF_DESCRIPTION "SRCDS Crash Handler" #define SMEXT_CONF_VERSION SM_FULL_VERSION -#define SMEXT_CONF_AUTHOR "Asher \"asherkin\" Baker" +#define SMEXT_CONF_AUTHOR "asherkin, kenzzer" #define SMEXT_CONF_URL "https://crash.limetech.org/" #define SMEXT_CONF_LOGTAG "CRASH" #define SMEXT_CONF_LICENSE "GPL" diff --git a/accelerator.games.txt b/gamedata/accelerator.games.txt similarity index 98% rename from accelerator.games.txt rename to gamedata/accelerator.games.txt index e6dd404..9549d81 100644 --- a/accelerator.games.txt +++ b/gamedata/accelerator.games.txt @@ -11,7 +11,7 @@ { "windows" "2" "linux" "2" - "mac" "2" + "linux64" "2" } } @@ -25,6 +25,7 @@ { "library" "engine" "linux" "@_Z7GetSpewPcj" + "linux64" "@_Z7GetSpewPcm" } } } diff --git a/patches/0001-Ignore-invalid-modules-rather-than-bailing-on-the-en.patch b/patches/0001-Ignore-invalid-modules-rather-than-bailing-on-the-en.patch index d47f76a..c90ad57 100644 --- a/patches/0001-Ignore-invalid-modules-rather-than-bailing-on-the-en.patch +++ b/patches/0001-Ignore-invalid-modules-rather-than-bailing-on-the-en.patch @@ -1,7 +1,7 @@ From 1f35257db226d6d0189cff0832a97cccc639c91a Mon Sep 17 00:00:00 2001 From: Asher Baker Date: Sun, 13 Jan 2019 12:34:45 +0000 -Subject: [PATCH 1/4] Ignore invalid modules rather than bailing on the entire +Subject: [PATCH 1/5] Ignore invalid modules rather than bailing on the entire module list --- @@ -9,10 +9,10 @@ Subject: [PATCH 1/4] Ignore invalid modules rather than bailing on the entire 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc -index 78faf77a..c4fda7b7 100644 +index 83e5a868..a7d564f2 100644 --- a/src/processor/minidump.cc +++ b/src/processor/minidump.cc -@@ -2774,7 +2774,7 @@ bool MinidumpModuleList::Read(uint32_t expected_size) { +@@ -3195,7 +3195,7 @@ bool MinidumpModuleList::Read(uint32_t expected_size) { BPLOG(ERROR) << "MinidumpModuleList could not read required module " "auxiliary data for module " << module_index << "/" << module_count; @@ -21,7 +21,7 @@ index 78faf77a..c4fda7b7 100644 } // It is safe to use module->code_file() after successfully calling -@@ -2786,7 +2786,14 @@ bool MinidumpModuleList::Read(uint32_t expected_size) { +@@ -3207,7 +3207,14 @@ bool MinidumpModuleList::Read(uint32_t expected_size) { BPLOG(ERROR) << "MinidumpModuleList found bad base address for module " << module_index << "/" << module_count << ", " << module.code_file(); @@ -37,7 +37,7 @@ index 78faf77a..c4fda7b7 100644 } // Some minidumps have additional modules in the list that are duplicates. -@@ -2813,7 +2820,7 @@ bool MinidumpModuleList::Read(uint32_t expected_size) { +@@ -3234,7 +3241,7 @@ bool MinidumpModuleList::Read(uint32_t expected_size) { << module_index << "/" << module_count << ", " << module.code_file() << ", " << HexString(base_address) << "+" << HexString(module_size); @@ -46,6 +46,3 @@ index 78faf77a..c4fda7b7 100644 } // If failed due to apparent range overlap the cause may be the client --- -2.21.0 - diff --git a/patches/0002-Write-FUNC-records-instead-of-PUBLIC-for-ELF-symbols.patch b/patches/0002-Write-FUNC-records-instead-of-PUBLIC-for-ELF-symbols.patch index a5fc147..08ce6b1 100644 --- a/patches/0002-Write-FUNC-records-instead-of-PUBLIC-for-ELF-symbols.patch +++ b/patches/0002-Write-FUNC-records-instead-of-PUBLIC-for-ELF-symbols.patch @@ -1,22 +1,22 @@ From 8aaf6e84a6704eb538f68a3e6fb6c3a8c93f1d8d Mon Sep 17 00:00:00 2001 From: Asher Baker Date: Sun, 13 Jan 2019 12:35:05 +0000 -Subject: [PATCH 2/4] Write FUNC records instead of PUBLIC for ELF symbols with +Subject: [PATCH 2/5] Write FUNC records instead of PUBLIC for ELF symbols with sizes - ---- + --- src/common/linux/elf_symbols_to_module.cc | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) + diff --git a/src/common/linux/elf_symbols_to_module.cc b/src/common/linux/elf_symbols_to_module.cc -index 562875e1..e11a5265 100644 +index 70d50f89..f21460bf 100644 --- a/src/common/linux/elf_symbols_to_module.cc +++ b/src/common/linux/elf_symbols_to_module.cc -@@ -156,19 +156,28 @@ bool ELFSymbolsToModule(const uint8_t *symtab_section, +@@ -163,19 +163,28 @@ bool ELFSymbolsToModule(const uint8_t* symtab_section, while(!iterator->at_end) { if (ELF32_ST_TYPE(iterator->info) == STT_FUNC && iterator->shndx != SHN_UNDEF) { -- Module::Extern *ext = new Module::Extern(iterator->value); +- auto ext = std::make_unique(iterator->value); - ext->name = SymbolString(iterator->name_offset, strings); + string name = SymbolString(iterator->name_offset, strings); #if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle. @@ -33,18 +33,15 @@ index 562875e1..e11a5265 100644 #endif +#if 1 + if (iterator->size) { -+ Module::Function *fun = new Module::Function(name, iterator->value); ++ Module::Function *fun = new Module::Function(module->AddStringToPool(name), iterator->value); + fun->ranges.push_back(Module::Range(iterator->value, iterator->size)); + module->AddFunction(fun); + } +#else + Module::Extern *ext = new Module::Extern(iterator->value); + ext->name = name; - module->AddExtern(ext); + module->AddExtern(std::move(ext)); +#endif } ++iterator; } --- -2.21.0 - diff --git a/patches/0003-Avoid-using-_ZNSsC1ERKSsjRKSaIcE-GLIBCXX-symbol-due-.patch b/patches/0003-Avoid-using-_ZNSsC1ERKSsjRKSaIcE-GLIBCXX-symbol-due-.patch deleted file mode 100644 index 8a613b7..0000000 --- a/patches/0003-Avoid-using-_ZNSsC1ERKSsjRKSaIcE-GLIBCXX-symbol-due-.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 21dfe5a22da02ed8bcd9fa1cca7c18c8c5310172 Mon Sep 17 00:00:00 2001 -From: patches -Date: Sun, 28 Apr 2019 18:45:57 +0000 -Subject: [PATCH 3/4] Avoid using _ZNSsC1ERKSsjRKSaIcE GLIBCXX symbol due to - version compat issues - ---- - src/common/dwarf/elf_reader.cc | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/src/common/dwarf/elf_reader.cc b/src/common/dwarf/elf_reader.cc -index 4135a51a..bfaaeefe 100644 ---- a/src/common/dwarf/elf_reader.cc -+++ b/src/common/dwarf/elf_reader.cc -@@ -1202,8 +1202,8 @@ const char *ElfReader::GetSectionInfoByName(const string §ion_name, - - bool ElfReader::SectionNamesMatch(const string &name, const string &sh_name) { - if ((name.find(".debug_", 0) == 0) && (sh_name.find(".zdebug_", 0) == 0)) { -- const string name_suffix(name, strlen(".debug_")); -- const string sh_name_suffix(sh_name, strlen(".zdebug_")); -+ const string name_suffix(&name.c_str()[strlen(".debug_")]); -+ const string sh_name_suffix(&sh_name.c_str()[strlen(".zdebug_")]); - return name_suffix == sh_name_suffix; - } - return name == sh_name; --- -2.21.0 - diff --git a/patches/0003-Support-compilation-on-VS-2015.patch b/patches/0003-Support-compilation-on-VS-2015.patch new file mode 100644 index 0000000..edbed52 --- /dev/null +++ b/patches/0003-Support-compilation-on-VS-2015.patch @@ -0,0 +1,25 @@ +From 2f217812634d5e6c56f0cf9e7a4c9b7fb390e954 Mon Sep 17 00:00:00 2001 +From: patches +Date: Sat, 20 Jul 2019 15:52:37 +0100 +Subject: [PATCH 3/5] Support compilation on VS 2015 + +--- + src/common/windows/pe_util.cc | 1 + + src/common/windows/pe_util.h | 2 +- + src/tools/windows/dump_syms/dump_syms.cc | 1 + + 3 files changed, 3 insertions(+), 1 deletion(-) + + +diff --git a/src/common/windows/pe_util.h b/src/common/windows/pe_util.h +index 6c6b364f..80aba5e5 100644 +--- a/src/common/windows/pe_util.h ++++ b/src/common/windows/pe_util.h +@@ -59,7 +59,7 @@ wstring GenerateDebugIdentifier(DWORD age, DWORD signature); + + // Converts |machine| enum value to the corresponding string used by Breakpad. + // The enum is IMAGE_FILE_MACHINE_*, contained in winnt.h. +-constexpr const wchar_t* FileHeaderMachineToCpuString(WORD machine) { ++static inline const wchar_t* FileHeaderMachineToCpuString(WORD machine) { + switch (machine) { + case IMAGE_FILE_MACHINE_I386: { + return L"x86"; diff --git a/patches/0004-Fix-Linux-a-out-include.patch b/patches/0004-Fix-Linux-a-out-include.patch new file mode 100644 index 0000000..8dab0fd --- /dev/null +++ b/patches/0004-Fix-Linux-a-out-include.patch @@ -0,0 +1,38 @@ +Subject: [PATCH 4/5] Fixes path to a.out.h file + +diff --git a/configure b/configure +index 3442e796..3e7c321c 100755 +--- a/configure ++++ b/configure +@@ -7532,11 +7532,16 @@ then : + printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h + + fi +-ac_fn_c_check_header_compile "$LINENO" "a.out.h" "ac_cv_header_a_out_h" "$ac_includes_default" ++ac_fn_c_check_header_compile "$LINENO" "linux/a.out.h" "ac_cv_header_a_out_h" "$ac_includes_default" + if test "x$ac_cv_header_a_out_h" = xyes + then : + printf "%s\n" "#define HAVE_A_OUT_H 1" >>confdefs.h +- ++else ++ ac_fn_c_check_header_compile "$LINENO" "a.out.h" "ac_cv_header_a_out_h" "$ac_includes_default" ++ if test "x$ac_cv_header_a_out_h" = xyes ++ then : ++ printf "%s\n" "#define HAVE_A_OUT_H_EX 1" >>confdefs.h ++ fi + fi + ac_fn_c_check_header_compile "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default" + if test "x$ac_cv_header_sys_mman_h" = xyes +diff --git a/src/common/stabs_reader.h b/src/common/stabs_reader.h +index 655683f1..1e6a76b8 100644 +--- a/src/common/stabs_reader.h ++++ b/src/common/stabs_reader.h +@@ -52,6 +52,8 @@ + #ifdef HAVE_MACH_O_NLIST_H + #include + #elif defined(HAVE_A_OUT_H) ++#include ++#elif defined(HAVE_A_OUT_H_EX) + #include + #endif + diff --git a/patches/0004-Support-compilation-on-VS-2015.patch b/patches/0004-Support-compilation-on-VS-2015.patch deleted file mode 100644 index 5f0e28b..0000000 --- a/patches/0004-Support-compilation-on-VS-2015.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 2f217812634d5e6c56f0cf9e7a4c9b7fb390e954 Mon Sep 17 00:00:00 2001 -From: patches -Date: Sat, 20 Jul 2019 15:52:37 +0100 -Subject: [PATCH 4/4] Support compilation on VS 2015 - ---- - src/common/windows/pe_util.cc | 1 + - src/common/windows/pe_util.h | 2 +- - src/tools/windows/dump_syms/dump_syms.cc | 1 + - 3 files changed, 3 insertions(+), 1 deletion(-) - -diff --git a/src/common/windows/pe_util.cc b/src/common/windows/pe_util.cc -index 6fa63fa3..03dcd142 100644 ---- a/src/common/windows/pe_util.cc -+++ b/src/common/windows/pe_util.cc -@@ -35,6 +35,7 @@ - #include - - #include -+#include - - #include "common/windows/string_utils-inl.h" - #include "common/windows/guid_string.h" -diff --git a/src/common/windows/pe_util.h b/src/common/windows/pe_util.h -index 634ba293..3eefa761 100644 ---- a/src/common/windows/pe_util.h -+++ b/src/common/windows/pe_util.h -@@ -60,7 +60,7 @@ wstring GenerateDebugIdentifier(DWORD age, DWORD signature); - - // Converts |machine| enum value to the corresponding string used by Breakpad. - // The enum is IMAGE_FILE_MACHINE_*, contained in winnt.h. --constexpr const wchar_t* FileHeaderMachineToCpuString(WORD machine) { -+static inline const wchar_t* FileHeaderMachineToCpuString(WORD machine) { - switch (machine) { - case IMAGE_FILE_MACHINE_I386: { - return L"x86"; -diff --git a/src/tools/windows/dump_syms/dump_syms.cc b/src/tools/windows/dump_syms/dump_syms.cc -index 5b7d1777..1f22cfc2 100644 ---- a/src/tools/windows/dump_syms/dump_syms.cc -+++ b/src/tools/windows/dump_syms/dump_syms.cc -@@ -33,6 +33,7 @@ - #include - #include - -+#include - #include - - #include "common/windows/pdb_source_line_writer.h" --- -2.21.0 - diff --git a/patches/0005-Add-LSS.patch b/patches/0005-Add-LSS.patch new file mode 100644 index 0000000..953fda8 --- /dev/null +++ b/patches/0005-Add-LSS.patch @@ -0,0 +1,5342 @@ +Subject: [PATCH 5/5] Insert the linux_syscall_support.h file as a patch + +diff --git a/src/third_party/lss/linux_syscall_support.h b/src/third_party/lss/linux_syscall_support.h +new file mode 100644 +index 00000000..8d09f6b0 +--- /dev/null ++++ b/src/third_party/lss/linux_syscall_support.h +@@ -0,0 +1,5333 @@ ++/* Copyright 2005-2011 Google LLC ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions are ++ * met: ++ * ++ * * Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * * Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following disclaimer ++ * in the documentation and/or other materials provided with the ++ * distribution. ++ * * Neither the name of Google LLC nor the names of its ++ * contributors may be used to endorse or promote products derived from ++ * this software without specific prior written permission. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * --- ++ * Author: Markus Gutschke ++ */ ++ ++/* This file includes Linux-specific support functions common to the ++ * coredumper and the thread lister; primarily, this is a collection ++ * of direct system calls, and a couple of symbols missing from ++ * standard header files. ++ * There are a few options that the including file can set to control ++ * the behavior of this file: ++ * ++ * SYS_CPLUSPLUS: ++ * The entire header file will normally be wrapped in 'extern "C" { }", ++ * making it suitable for compilation as both C and C++ source. If you ++ * do not want to do this, you can set the SYS_CPLUSPLUS macro to inhibit ++ * the wrapping. N.B. doing so will suppress inclusion of all prerequisite ++ * system header files, too. It is the caller's responsibility to provide ++ * the necessary definitions. ++ * ++ * SYS_ERRNO: ++ * All system calls will update "errno" unless overridden by setting the ++ * SYS_ERRNO macro prior to including this file. SYS_ERRNO should be ++ * an l-value. ++ * ++ * SYS_INLINE: ++ * New symbols will be defined "static inline", unless overridden by ++ * the SYS_INLINE macro. ++ * ++ * SYS_LINUX_SYSCALL_SUPPORT_H ++ * This macro is used to avoid multiple inclusions of this header file. ++ * If you need to include this file more than once, make sure to ++ * unset SYS_LINUX_SYSCALL_SUPPORT_H before each inclusion. ++ * ++ * SYS_PREFIX: ++ * New system calls will have a prefix of "sys_" unless overridden by ++ * the SYS_PREFIX macro. Valid values for this macro are [0..9] which ++ * results in prefixes "sys[0..9]_". It is also possible to set this ++ * macro to -1, which avoids all prefixes. ++ * ++ * SYS_SYSCALL_ENTRYPOINT: ++ * Some applications (such as sandboxes that filter system calls), need ++ * to be able to run custom-code each time a system call is made. If this ++ * macro is defined, it expands to the name of a "common" symbol. If ++ * this symbol is assigned a non-NULL pointer value, it is used as the ++ * address of the system call entrypoint. ++ * A pointer to this symbol can be obtained by calling ++ * get_syscall_entrypoint() ++ * ++ * This file defines a few internal symbols that all start with "LSS_". ++ * Do not access these symbols from outside this file. They are not part ++ * of the supported API. ++ */ ++#ifndef SYS_LINUX_SYSCALL_SUPPORT_H ++#define SYS_LINUX_SYSCALL_SUPPORT_H ++ ++/* We currently only support x86-32, x86-64, ARM, MIPS, PPC, s390 and s390x ++ * on Linux. ++ * Porting to other related platforms should not be difficult. ++ */ ++#if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || \ ++ defined(__mips__) || defined(__PPC__) || defined(__ARM_EABI__) || \ ++ defined(__aarch64__) || defined(__s390__) || defined(__e2k__) || \ ++ (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch_lp64)) \ ++ && (defined(__linux) || defined(__ANDROID__)) ++ ++#ifndef SYS_CPLUSPLUS ++#ifdef __cplusplus ++/* Some system header files in older versions of gcc neglect to properly ++ * handle being included from C++. As it appears to be harmless to have ++ * multiple nested 'extern "C"' blocks, just add another one here. ++ */ ++extern "C" { ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef __mips__ ++/* Include definitions of the ABI currently in use. */ ++#ifdef __ANDROID__ ++/* Android doesn't have sgidefs.h, but does have asm/sgidefs.h, ++ * which has the definitions we need. ++ */ ++#include ++#else ++#include ++#endif ++#endif ++#endif ++ ++/* Some libcs, for example Android NDK and musl, #define these ++ * macros as aliases to their non-64 counterparts. To avoid naming ++ * conflict, remove them. ++ * ++ * These are restored by the corresponding #pragma pop_macro near ++ * the end of this file. ++ */ ++#pragma push_macro("stat64") ++#pragma push_macro("fstat64") ++#pragma push_macro("lstat64") ++#pragma push_macro("pread64") ++#pragma push_macro("pwrite64") ++#pragma push_macro("getdents64") ++#undef stat64 ++#undef fstat64 ++#undef lstat64 ++#undef pread64 ++#undef pwrite64 ++#undef getdents64 ++ ++#if defined(__ANDROID__) && defined(__x86_64__) ++// A number of x86_64 syscalls are blocked by seccomp on recent Android; ++// undefine them so that modern alternatives will be used instead where ++// possible. ++// The alternative syscalls have been sanity checked against linux-3.4+; ++// older versions might not work. ++# undef __NR_getdents ++# undef __NR_dup2 ++# undef __NR_fork ++# undef __NR_getpgrp ++# undef __NR_open ++# undef __NR_poll ++# undef __NR_readlink ++# undef __NR_stat ++# undef __NR_unlink ++# undef __NR_pipe ++#endif ++ ++#if defined(__ANDROID__) ++// waitpid is blocked by seccomp on all architectures on recent Android. ++# undef __NR_waitpid ++#endif ++ ++/* As glibc often provides subtly incompatible data structures (and implicit ++ * wrapper functions that convert them), we provide our own kernel data ++ * structures for use by the system calls. ++ * These structures have been developed by using Linux 2.6.23 headers for ++ * reference. Note though, we do not care about exact API compatibility ++ * with the kernel, and in fact the kernel often does not have a single ++ * API that works across architectures. Instead, we try to mimic the glibc ++ * API where reasonable, and only guarantee ABI compatibility with the ++ * kernel headers. ++ * Most notably, here are a few changes that were made to the structures ++ * defined by kernel headers: ++ * ++ * - we only define structures, but not symbolic names for kernel data ++ * types. For the latter, we directly use the native C datatype ++ * (i.e. "unsigned" instead of "mode_t"). ++ * - in a few cases, it is possible to define identical structures for ++ * both 32bit (e.g. i386) and 64bit (e.g. x86-64) platforms by ++ * standardizing on the 64bit version of the data types. In particular, ++ * this means that we use "unsigned" where the 32bit headers say ++ * "unsigned long". ++ * - overall, we try to minimize the number of cases where we need to ++ * conditionally define different structures. ++ * - the "struct kernel_sigaction" class of structures have been ++ * modified to more closely mimic glibc's API by introducing an ++ * anonymous union for the function pointer. ++ * - a small number of field names had to have an underscore appended to ++ * them, because glibc defines a global macro by the same name. ++ */ ++ ++/* include/linux/dirent.h */ ++struct kernel_dirent64 { ++ unsigned long long d_ino; ++ long long d_off; ++ unsigned short d_reclen; ++ unsigned char d_type; ++ char d_name[256]; ++}; ++ ++/* include/linux/dirent.h */ ++#if !defined(__NR_getdents) ++// when getdents is not available, getdents64 is used for both. ++#define kernel_dirent kernel_dirent64 ++#else ++struct kernel_dirent { ++ long d_ino; ++ long d_off; ++ unsigned short d_reclen; ++ char d_name[256]; ++}; ++#endif ++ ++/* include/linux/uio.h */ ++struct kernel_iovec { ++ void *iov_base; ++ unsigned long iov_len; ++}; ++ ++/* include/linux/socket.h */ ++struct kernel_msghdr { ++ void *msg_name; ++ int msg_namelen; ++ struct kernel_iovec*msg_iov; ++ unsigned long msg_iovlen; ++ void *msg_control; ++ unsigned long msg_controllen; ++ unsigned msg_flags; ++}; ++ ++/* include/asm-generic/poll.h */ ++struct kernel_pollfd { ++ int fd; ++ short events; ++ short revents; ++}; ++ ++/* include/linux/resource.h */ ++struct kernel_rlimit { ++ unsigned long rlim_cur; ++ unsigned long rlim_max; ++}; ++ ++/* include/linux/time.h */ ++struct kernel_timespec { ++ long tv_sec; ++ long tv_nsec; ++}; ++ ++/* include/linux/time.h */ ++struct kernel_timeval { ++ long tv_sec; ++ long tv_usec; ++}; ++ ++/* include/linux/time.h */ ++struct kernel_itimerval { ++ struct kernel_timeval it_interval; ++ struct kernel_timeval it_value; ++}; ++ ++/* include/linux/resource.h */ ++struct kernel_rusage { ++ struct kernel_timeval ru_utime; ++ struct kernel_timeval ru_stime; ++ long ru_maxrss; ++ long ru_ixrss; ++ long ru_idrss; ++ long ru_isrss; ++ long ru_minflt; ++ long ru_majflt; ++ long ru_nswap; ++ long ru_inblock; ++ long ru_oublock; ++ long ru_msgsnd; ++ long ru_msgrcv; ++ long ru_nsignals; ++ long ru_nvcsw; ++ long ru_nivcsw; ++}; ++ ++#if defined(__i386__) || defined(__ARM_EABI__) || defined(__ARM_ARCH_3__) \ ++ || defined(__PPC__) || (defined(__s390__) && !defined(__s390x__)) \ ++ || defined(__e2k__) ++ ++/* include/asm-{arm,i386,mips,ppc}/signal.h */ ++struct kernel_old_sigaction { ++ union { ++ void (*sa_handler_)(int); ++ void (*sa_sigaction_)(int, siginfo_t *, void *); ++ }; ++ unsigned long sa_mask; ++ unsigned long sa_flags; ++ void (*sa_restorer)(void); ++} __attribute__((packed,aligned(4))); ++#elif (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) ++ #define kernel_old_sigaction kernel_sigaction ++#elif defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64) ++ // No kernel_old_sigaction defined for arm64 riscv and loongarch64. ++#endif ++ ++/* Some kernel functions (e.g. sigaction() in 2.6.23) require that the ++ * exactly match the size of the signal set, even though the API was ++ * intended to be extensible. We define our own KERNEL_NSIG to deal with ++ * this. ++ * Please note that glibc provides signals [1.._NSIG-1], whereas the ++ * kernel (and this header) provides the range [1..KERNEL_NSIG]. The ++ * actual number of signals is obviously the same, but the constants ++ * differ by one. ++ */ ++#ifdef __mips__ ++#define KERNEL_NSIG 128 ++#else ++#define KERNEL_NSIG 64 ++#endif ++ ++/* include/asm-{arm,aarch64,i386,mips,x86_64}/signal.h */ ++struct kernel_sigset_t { ++ unsigned long sig[(KERNEL_NSIG + 8*sizeof(unsigned long) - 1)/ ++ (8*sizeof(unsigned long))]; ++}; ++ ++/* include/asm-{arm,i386,mips,x86_64,ppc}/signal.h */ ++struct kernel_sigaction { ++#ifdef __mips__ ++ unsigned long sa_flags; ++ union { ++ void (*sa_handler_)(int); ++ void (*sa_sigaction_)(int, siginfo_t *, void *); ++ }; ++ struct kernel_sigset_t sa_mask; ++#else ++ union { ++ void (*sa_handler_)(int); ++ void (*sa_sigaction_)(int, siginfo_t *, void *); ++ }; ++ unsigned long sa_flags; ++#if !defined(__riscv) && !defined(__loongarch_lp64) ++ void (*sa_restorer)(void); ++#endif ++ struct kernel_sigset_t sa_mask; ++#endif ++}; ++ ++/* include/linux/socket.h */ ++struct kernel_sockaddr { ++ unsigned short sa_family; ++ char sa_data[14]; ++}; ++ ++/* include/asm-{arm,aarch64,i386,mips,ppc,s390}/stat.h */ ++#ifdef __mips__ ++#if _MIPS_SIM == _MIPS_SIM_ABI64 ++typedef unsigned long long kernel_blkcnt_t; ++typedef unsigned kernel_blksize_t; ++typedef unsigned kernel_dev_t; ++typedef unsigned kernel_gid_t; ++typedef unsigned long long kernel_ino_t; ++typedef unsigned kernel_mode_t; ++typedef unsigned kernel_nlink_t; ++typedef long long kernel_off_t; ++typedef unsigned kernel_time_t; ++typedef unsigned kernel_uid_t; ++struct kernel_stat { ++#else ++struct kernel_stat64 { ++#endif ++ unsigned st_dev; ++ unsigned __pad0[3]; ++ unsigned long long st_ino; ++ unsigned st_mode; ++ unsigned st_nlink; ++ unsigned st_uid; ++ unsigned st_gid; ++ unsigned st_rdev; ++ unsigned __pad1[3]; ++ long long st_size; ++ unsigned st_atime_; ++ unsigned st_atime_nsec_; ++ unsigned st_mtime_; ++ unsigned st_mtime_nsec_; ++ unsigned st_ctime_; ++ unsigned st_ctime_nsec_; ++ unsigned st_blksize; ++ unsigned __pad2; ++ unsigned long long st_blocks; ++}; ++#elif defined __PPC__ ++struct kernel_stat64 { ++ unsigned long long st_dev; ++ unsigned long long st_ino; ++ unsigned st_mode; ++ unsigned st_nlink; ++ unsigned st_uid; ++ unsigned st_gid; ++ unsigned long long st_rdev; ++ unsigned short int __pad2; ++ long long st_size; ++ long st_blksize; ++ long long st_blocks; ++ long st_atime_; ++ unsigned long st_atime_nsec_; ++ long st_mtime_; ++ unsigned long st_mtime_nsec_; ++ long st_ctime_; ++ unsigned long st_ctime_nsec_; ++ unsigned long __unused4; ++ unsigned long __unused5; ++}; ++#elif defined(__e2k__) ++struct kernel_stat64 { ++ unsigned long long st_dev; ++ unsigned long long st_ino; ++ unsigned int st_mode; ++ unsigned int st_nlink; ++ unsigned int st_uid; ++ unsigned int st_gid; ++ unsigned long long st_rdev; ++ long long st_size; ++ int st_blksize; ++ int __pad2; ++ unsigned long long st_blocks; ++ int st_atime_; ++ unsigned int st_atime_nsec_; ++ int st_mtime_; ++ unsigned int st_mtime_nsec_; ++ int st_ctime_; ++ unsigned int st_ctime_nsec_; ++ unsigned int __unused4; ++ unsigned int __unused5; ++}; ++#else ++struct kernel_stat64 { ++ unsigned long long st_dev; ++ unsigned char __pad0[4]; ++ unsigned __st_ino; ++ unsigned st_mode; ++ unsigned st_nlink; ++ unsigned st_uid; ++ unsigned st_gid; ++ unsigned long long st_rdev; ++ unsigned char __pad3[4]; ++ long long st_size; ++ unsigned st_blksize; ++ unsigned long long st_blocks; ++ unsigned st_atime_; ++ unsigned st_atime_nsec_; ++ unsigned st_mtime_; ++ unsigned st_mtime_nsec_; ++ unsigned st_ctime_; ++ unsigned st_ctime_nsec_; ++ unsigned long long st_ino; ++}; ++#endif ++ ++/* include/asm-{arm,aarch64,i386,mips,x86_64,ppc,s390}/stat.h */ ++#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) ++typedef unsigned kernel_blkcnt_t; ++typedef unsigned kernel_blksize_t; ++typedef unsigned short kernel_dev_t; ++typedef unsigned short kernel_gid_t; ++typedef unsigned kernel_ino_t; ++typedef unsigned short kernel_mode_t; ++typedef unsigned short kernel_nlink_t; ++typedef unsigned kernel_off_t; ++typedef unsigned kernel_time_t; ++typedef unsigned short kernel_uid_t; ++struct kernel_stat { ++ /* The kernel headers suggest that st_dev and st_rdev should be 32bit ++ * quantities encoding 12bit major and 20bit minor numbers in an interleaved ++ * format. In reality, we do not see useful data in the top bits. So, ++ * we'll leave the padding in here, until we find a better solution. ++ */ ++ kernel_dev_t st_dev; ++ short pad1; ++ kernel_ino_t st_ino; ++ kernel_mode_t st_mode; ++ kernel_nlink_t st_nlink; ++ kernel_uid_t st_uid; ++ kernel_gid_t st_gid; ++ kernel_dev_t st_rdev; ++ short pad2; ++ kernel_off_t st_size; ++ kernel_blksize_t st_blksize; ++ kernel_blkcnt_t st_blocks; ++ kernel_time_t st_atime_; ++ unsigned st_atime_nsec_; ++ kernel_time_t st_mtime_; ++ unsigned st_mtime_nsec_; ++ kernel_time_t st_ctime_; ++ unsigned st_ctime_nsec_; ++ unsigned __unused4; ++ unsigned __unused5; ++}; ++#elif defined(__x86_64__) ++typedef int64_t kernel_blkcnt_t; ++typedef int64_t kernel_blksize_t; ++typedef uint64_t kernel_dev_t; ++typedef unsigned kernel_gid_t; ++typedef uint64_t kernel_ino_t; ++typedef unsigned kernel_mode_t; ++typedef uint64_t kernel_nlink_t; ++typedef int64_t kernel_off_t; ++typedef uint64_t kernel_time_t; ++typedef unsigned kernel_uid_t; ++struct kernel_stat { ++ kernel_dev_t st_dev; ++ kernel_ino_t st_ino; ++ kernel_nlink_t st_nlink; ++ kernel_mode_t st_mode; ++ kernel_uid_t st_uid; ++ kernel_gid_t st_gid; ++ unsigned __pad0; ++ kernel_dev_t st_rdev; ++ kernel_off_t st_size; ++ kernel_blksize_t st_blksize; ++ kernel_blkcnt_t st_blocks; ++ kernel_time_t st_atime_; ++ uint64_t st_atime_nsec_; ++ kernel_time_t st_mtime_; ++ uint64_t st_mtime_nsec_; ++ kernel_time_t st_ctime_; ++ uint64_t st_ctime_nsec_; ++ int64_t __unused4[3]; ++}; ++#elif defined(__PPC__) ++typedef unsigned long kernel_blkcnt_t; ++typedef unsigned long kernel_blksize_t; ++typedef unsigned kernel_dev_t; ++typedef unsigned kernel_gid_t; ++typedef unsigned long kernel_ino_t; ++typedef unsigned long kernel_mode_t; ++typedef unsigned short kernel_nlink_t; ++typedef long kernel_off_t; ++typedef unsigned long kernel_time_t; ++typedef unsigned kernel_uid_t; ++struct kernel_stat { ++ kernel_dev_t st_dev; ++ kernel_ino_t st_ino; ++ kernel_mode_t st_mode; ++ kernel_nlink_t st_nlink; ++ kernel_gid_t st_uid; ++ kernel_uid_t st_gid; ++ kernel_dev_t st_rdev; ++ kernel_off_t st_size; ++ kernel_blksize_t st_blksize; ++ kernel_blkcnt_t st_blocks; ++ kernel_time_t st_atime_; ++ unsigned long st_atime_nsec_; ++ kernel_time_t st_mtime_; ++ unsigned long st_mtime_nsec_; ++ kernel_time_t st_ctime_; ++ unsigned long st_ctime_nsec_; ++ unsigned long __unused4; ++ unsigned long __unused5; ++}; ++#elif (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI64) ++typedef int kernel_blkcnt_t; ++typedef int kernel_blksize_t; ++typedef unsigned kernel_dev_t; ++typedef unsigned kernel_gid_t; ++typedef unsigned kernel_ino_t; ++typedef unsigned kernel_mode_t; ++typedef unsigned kernel_nlink_t; ++typedef long kernel_off_t; ++typedef long kernel_time_t; ++typedef unsigned kernel_uid_t; ++struct kernel_stat { ++ kernel_dev_t st_dev; ++ int st_pad1[3]; ++ kernel_ino_t st_ino; ++ kernel_mode_t st_mode; ++ kernel_nlink_t st_nlink; ++ kernel_uid_t st_uid; ++ kernel_gid_t st_gid; ++ kernel_dev_t st_rdev; ++ int st_pad2[2]; ++ kernel_off_t st_size; ++ int st_pad3; ++ kernel_time_t st_atime_; ++ long st_atime_nsec_; ++ kernel_time_t st_mtime_; ++ long st_mtime_nsec_; ++ kernel_time_t st_ctime_; ++ long st_ctime_nsec_; ++ kernel_blksize_t st_blksize; ++ kernel_blkcnt_t st_blocks; ++ int st_pad4[14]; ++}; ++#elif defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64) ++typedef long kernel_blkcnt_t; ++typedef int kernel_blksize_t; ++typedef unsigned long kernel_dev_t; ++typedef unsigned int kernel_gid_t; ++typedef unsigned long kernel_ino_t; ++typedef unsigned int kernel_mode_t; ++typedef unsigned int kernel_nlink_t; ++typedef long kernel_off_t; ++typedef long kernel_time_t; ++typedef unsigned int kernel_uid_t; ++struct kernel_stat { ++ kernel_dev_t st_dev; ++ kernel_ino_t st_ino; ++ kernel_mode_t st_mode; ++ kernel_nlink_t st_nlink; ++ kernel_uid_t st_uid; ++ kernel_gid_t st_gid; ++ kernel_dev_t st_rdev; ++ unsigned long __pad1; ++ kernel_off_t st_size; ++ kernel_blksize_t st_blksize; ++ int __pad2; ++ kernel_blkcnt_t st_blocks; ++ kernel_time_t st_atime_; ++ unsigned long st_atime_nsec_; ++ kernel_time_t st_mtime_; ++ unsigned long st_mtime_nsec_; ++ kernel_time_t st_ctime_; ++ unsigned long st_ctime_nsec_; ++ unsigned int __unused4; ++ unsigned int __unused5; ++}; ++#elif defined(__s390x__) ++typedef long kernel_blkcnt_t; ++typedef unsigned long kernel_blksize_t; ++typedef unsigned long kernel_dev_t; ++typedef unsigned int kernel_gid_t; ++typedef unsigned long kernel_ino_t; ++typedef unsigned int kernel_mode_t; ++typedef unsigned long kernel_nlink_t; ++typedef unsigned long kernel_off_t; ++typedef unsigned long kernel_time_t; ++typedef unsigned int kernel_uid_t; ++struct kernel_stat { ++ kernel_dev_t st_dev; ++ kernel_ino_t st_ino; ++ kernel_nlink_t st_nlink; ++ kernel_mode_t st_mode; ++ kernel_uid_t st_uid; ++ kernel_gid_t st_gid; ++ unsigned int __pad1; ++ kernel_dev_t st_rdev; ++ kernel_off_t st_size; ++ kernel_time_t st_atime_; ++ unsigned long st_atime_nsec_; ++ kernel_time_t st_mtime_; ++ unsigned long st_mtime_nsec_; ++ kernel_time_t st_ctime_; ++ unsigned long st_ctime_nsec_; ++ kernel_blksize_t st_blksize; ++ kernel_blkcnt_t st_blocks; ++ unsigned long __unused[3]; ++}; ++#elif defined(__s390__) ++typedef unsigned long kernel_blkcnt_t; ++typedef unsigned long kernel_blksize_t; ++typedef unsigned short kernel_dev_t; ++typedef unsigned short kernel_gid_t; ++typedef unsigned long kernel_ino_t; ++typedef unsigned short kernel_mode_t; ++typedef unsigned short kernel_nlink_t; ++typedef unsigned long kernel_off_t; ++typedef unsigned long kernel_time_t; ++typedef unsigned short kernel_uid_t; ++struct kernel_stat { ++ kernel_dev_t st_dev; ++ unsigned short __pad1; ++ kernel_ino_t st_ino; ++ kernel_mode_t st_mode; ++ kernel_nlink_t st_nlink; ++ kernel_uid_t st_uid; ++ kernel_gid_t st_gid; ++ kernel_dev_t st_rdev; ++ unsigned short __pad2; ++ kernel_off_t st_size; ++ kernel_blksize_t st_blksize; ++ kernel_blkcnt_t st_blocks; ++ kernel_time_t st_atime_; ++ unsigned long st_atime_nsec_; ++ kernel_time_t st_mtime_; ++ unsigned long st_mtime_nsec_; ++ kernel_time_t st_ctime_; ++ unsigned long st_ctime_nsec_; ++ unsigned long __unused4; ++ unsigned long __unused5; ++}; ++#elif defined(__e2k__) ++typedef unsigned long kernel_blkcnt_t; ++typedef unsigned long kernel_blksize_t; ++typedef unsigned long kernel_dev_t; ++typedef unsigned int kernel_gid_t; ++typedef unsigned long kernel_ino_t; ++typedef unsigned int kernel_mode_t; ++typedef unsigned long kernel_nlink_t; ++typedef unsigned long kernel_off_t; ++typedef unsigned long kernel_time_t; ++typedef unsigned int kernel_uid_t; ++struct kernel_stat { ++ kernel_dev_t st_dev; ++ kernel_ino_t st_ino; ++ kernel_mode_t st_mode; ++ kernel_nlink_t st_nlink; ++ kernel_uid_t st_uid; ++ kernel_gid_t st_gid; ++ kernel_dev_t st_rdev; ++ kernel_off_t st_size; ++ kernel_blksize_t st_blksize; ++ kernel_blkcnt_t st_blocks; ++ kernel_time_t st_atime_; ++ unsigned long st_atime_nsec_; ++ kernel_time_t st_mtime_; ++ unsigned long st_mtime_nsec_; ++ kernel_time_t st_ctime_; ++ unsigned long st_ctime_nsec_; ++}; ++#endif ++ ++/* include/asm-{arm,aarch64,i386,mips,x86_64,ppc,s390}/statfs.h */ ++#ifdef __mips__ ++#if _MIPS_SIM != _MIPS_SIM_ABI64 ++struct kernel_statfs64 { ++ unsigned long f_type; ++ unsigned long f_bsize; ++ unsigned long f_frsize; ++ unsigned long __pad; ++ unsigned long long f_blocks; ++ unsigned long long f_bfree; ++ unsigned long long f_files; ++ unsigned long long f_ffree; ++ unsigned long long f_bavail; ++ struct { int val[2]; } f_fsid; ++ unsigned long f_namelen; ++ unsigned long f_spare[6]; ++}; ++#endif ++#elif defined(__s390__) ++/* See also arch/s390/include/asm/compat.h */ ++struct kernel_statfs64 { ++ unsigned int f_type; ++ unsigned int f_bsize; ++ unsigned long long f_blocks; ++ unsigned long long f_bfree; ++ unsigned long long f_bavail; ++ unsigned long long f_files; ++ unsigned long long f_ffree; ++ struct { int val[2]; } f_fsid; ++ unsigned int f_namelen; ++ unsigned int f_frsize; ++ unsigned int f_flags; ++ unsigned int f_spare[4]; ++}; ++#elif !defined(__x86_64__) ++struct kernel_statfs64 { ++ unsigned long f_type; ++ unsigned long f_bsize; ++ unsigned long long f_blocks; ++ unsigned long long f_bfree; ++ unsigned long long f_bavail; ++ unsigned long long f_files; ++ unsigned long long f_ffree; ++ struct { int val[2]; } f_fsid; ++ unsigned long f_namelen; ++ unsigned long f_frsize; ++ unsigned long f_spare[5]; ++}; ++#endif ++ ++/* include/asm-{arm,i386,mips,x86_64,ppc,generic,s390}/statfs.h */ ++#ifdef __mips__ ++struct kernel_statfs { ++ long f_type; ++ long f_bsize; ++ long f_frsize; ++ long f_blocks; ++ long f_bfree; ++ long f_files; ++ long f_ffree; ++ long f_bavail; ++ struct { int val[2]; } f_fsid; ++ long f_namelen; ++ long f_spare[6]; ++}; ++#elif defined(__x86_64__) ++struct kernel_statfs { ++ /* x86_64 actually defines all these fields as signed, whereas all other */ ++ /* platforms define them as unsigned. Leaving them at unsigned should not */ ++ /* cause any problems. Make sure these are 64-bit even on x32. */ ++ uint64_t f_type; ++ uint64_t f_bsize; ++ uint64_t f_blocks; ++ uint64_t f_bfree; ++ uint64_t f_bavail; ++ uint64_t f_files; ++ uint64_t f_ffree; ++ struct { int val[2]; } f_fsid; ++ uint64_t f_namelen; ++ uint64_t f_frsize; ++ uint64_t f_spare[5]; ++}; ++#elif defined(__s390__) ++struct kernel_statfs { ++ unsigned int f_type; ++ unsigned int f_bsize; ++ unsigned long f_blocks; ++ unsigned long f_bfree; ++ unsigned long f_bavail; ++ unsigned long f_files; ++ unsigned long f_ffree; ++ struct { int val[2]; } f_fsid; ++ unsigned int f_namelen; ++ unsigned int f_frsize; ++ unsigned int f_flags; ++ unsigned int f_spare[4]; ++}; ++#else ++struct kernel_statfs { ++ unsigned long f_type; ++ unsigned long f_bsize; ++ unsigned long f_blocks; ++ unsigned long f_bfree; ++ unsigned long f_bavail; ++ unsigned long f_files; ++ unsigned long f_ffree; ++ struct { int val[2]; } f_fsid; ++ unsigned long f_namelen; ++ unsigned long f_frsize; ++ unsigned long f_spare[5]; ++}; ++#endif ++ ++struct kernel_statx_timestamp { ++ int64_t tv_sec; ++ uint32_t tv_nsec; ++ int32_t __reserved; ++}; ++ ++struct kernel_statx { ++ uint32_t stx_mask; ++ uint32_t stx_blksize; ++ uint64_t stx_attributes; ++ uint32_t stx_nlink; ++ uint32_t stx_uid; ++ uint32_t stx_gid; ++ uint16_t stx_mode; ++ uint16_t __spare0[1]; ++ uint64_t stx_ino; ++ uint64_t stx_size; ++ uint64_t stx_blocks; ++ uint64_t stx_attributes_mask; ++ struct kernel_statx_timestamp stx_atime; ++ struct kernel_statx_timestamp stx_btime; ++ struct kernel_statx_timestamp stx_ctime; ++ struct kernel_statx_timestamp stx_mtime; ++ uint32_t stx_rdev_major; ++ uint32_t stx_rdev_minor; ++ uint32_t stx_dev_major; ++ uint32_t stx_dev_minor; ++ uint64_t stx_mnt_id; ++ uint64_t __spare2; ++ uint64_t __spare3[12]; ++}; ++ ++/* Definitions missing from the standard header files */ ++#ifndef O_DIRECTORY ++#if defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || defined(__aarch64__) ++#define O_DIRECTORY 0040000 ++#else ++#define O_DIRECTORY 0200000 ++#endif ++#endif ++#ifndef NT_PRXFPREG ++#define NT_PRXFPREG 0x46e62b7f ++#endif ++#ifndef PTRACE_GETFPXREGS ++#define PTRACE_GETFPXREGS ((enum __ptrace_request)18) ++#endif ++#ifndef PR_GET_DUMPABLE ++#define PR_GET_DUMPABLE 3 ++#endif ++#ifndef PR_SET_DUMPABLE ++#define PR_SET_DUMPABLE 4 ++#endif ++#ifndef PR_GET_SECCOMP ++#define PR_GET_SECCOMP 21 ++#endif ++#ifndef PR_SET_SECCOMP ++#define PR_SET_SECCOMP 22 ++#endif ++#ifndef AT_FDCWD ++#define AT_FDCWD (-100) ++#endif ++#ifndef AT_SYMLINK_NOFOLLOW ++#define AT_SYMLINK_NOFOLLOW 0x100 ++#endif ++#ifndef AT_REMOVEDIR ++#define AT_REMOVEDIR 0x200 ++#endif ++#ifndef AT_NO_AUTOMOUNT ++#define AT_NO_AUTOMOUNT 0x800 ++#endif ++#ifndef AT_EMPTY_PATH ++#define AT_EMPTY_PATH 0x1000 ++#endif ++#ifndef STATX_BASIC_STATS ++#define STATX_BASIC_STATS 0x000007ffU ++#endif ++#ifndef AT_STATX_SYNC_AS_STAT ++#define AT_STATX_SYNC_AS_STAT 0x0000 ++#endif ++#ifndef MREMAP_FIXED ++#define MREMAP_FIXED 2 ++#endif ++#ifndef SA_RESTORER ++#define SA_RESTORER 0x04000000 ++#endif ++#ifndef CPUCLOCK_PROF ++#define CPUCLOCK_PROF 0 ++#endif ++#ifndef CPUCLOCK_VIRT ++#define CPUCLOCK_VIRT 1 ++#endif ++#ifndef CPUCLOCK_SCHED ++#define CPUCLOCK_SCHED 2 ++#endif ++#ifndef CPUCLOCK_PERTHREAD_MASK ++#define CPUCLOCK_PERTHREAD_MASK 4 ++#endif ++#ifndef MAKE_PROCESS_CPUCLOCK ++#define MAKE_PROCESS_CPUCLOCK(pid, clock) \ ++ ((int)(~(unsigned)(pid) << 3) | (int)(clock)) ++#endif ++#ifndef MAKE_THREAD_CPUCLOCK ++#define MAKE_THREAD_CPUCLOCK(tid, clock) \ ++ ((int)(~(unsigned)(tid) << 3) | \ ++ (int)((clock) | CPUCLOCK_PERTHREAD_MASK)) ++#endif ++ ++#ifndef FUTEX_WAIT ++#define FUTEX_WAIT 0 ++#endif ++#ifndef FUTEX_WAKE ++#define FUTEX_WAKE 1 ++#endif ++#ifndef FUTEX_FD ++#define FUTEX_FD 2 ++#endif ++#ifndef FUTEX_REQUEUE ++#define FUTEX_REQUEUE 3 ++#endif ++#ifndef FUTEX_CMP_REQUEUE ++#define FUTEX_CMP_REQUEUE 4 ++#endif ++#ifndef FUTEX_WAKE_OP ++#define FUTEX_WAKE_OP 5 ++#endif ++#ifndef FUTEX_LOCK_PI ++#define FUTEX_LOCK_PI 6 ++#endif ++#ifndef FUTEX_UNLOCK_PI ++#define FUTEX_UNLOCK_PI 7 ++#endif ++#ifndef FUTEX_TRYLOCK_PI ++#define FUTEX_TRYLOCK_PI 8 ++#endif ++#ifndef FUTEX_PRIVATE_FLAG ++#define FUTEX_PRIVATE_FLAG 128 ++#endif ++#ifndef FUTEX_CMD_MASK ++#define FUTEX_CMD_MASK ~FUTEX_PRIVATE_FLAG ++#endif ++#ifndef FUTEX_WAIT_PRIVATE ++#define FUTEX_WAIT_PRIVATE (FUTEX_WAIT | FUTEX_PRIVATE_FLAG) ++#endif ++#ifndef FUTEX_WAKE_PRIVATE ++#define FUTEX_WAKE_PRIVATE (FUTEX_WAKE | FUTEX_PRIVATE_FLAG) ++#endif ++#ifndef FUTEX_REQUEUE_PRIVATE ++#define FUTEX_REQUEUE_PRIVATE (FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG) ++#endif ++#ifndef FUTEX_CMP_REQUEUE_PRIVATE ++#define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_CMP_REQUEUE | FUTEX_PRIVATE_FLAG) ++#endif ++#ifndef FUTEX_WAKE_OP_PRIVATE ++#define FUTEX_WAKE_OP_PRIVATE (FUTEX_WAKE_OP | FUTEX_PRIVATE_FLAG) ++#endif ++#ifndef FUTEX_LOCK_PI_PRIVATE ++#define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG) ++#endif ++#ifndef FUTEX_UNLOCK_PI_PRIVATE ++#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG) ++#endif ++#ifndef FUTEX_TRYLOCK_PI_PRIVATE ++#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG) ++#endif ++ ++ ++#if defined(__x86_64__) ++#ifndef ARCH_SET_GS ++#define ARCH_SET_GS 0x1001 ++#endif ++#ifndef ARCH_GET_GS ++#define ARCH_GET_GS 0x1004 ++#endif ++#endif ++ ++#if defined(__i386__) ++#ifndef __NR_quotactl ++#define __NR_quotactl 131 ++#endif ++#ifndef __NR_setresuid ++#define __NR_setresuid 164 ++#define __NR_getresuid 165 ++#define __NR_setresgid 170 ++#define __NR_getresgid 171 ++#endif ++#ifndef __NR_rt_sigaction ++#define __NR_rt_sigreturn 173 ++#define __NR_rt_sigaction 174 ++#define __NR_rt_sigprocmask 175 ++#define __NR_rt_sigpending 176 ++#define __NR_rt_sigsuspend 179 ++#endif ++#ifndef __NR_pread64 ++#define __NR_pread64 180 ++#endif ++#ifndef __NR_pwrite64 ++#define __NR_pwrite64 181 ++#endif ++#ifndef __NR_ugetrlimit ++#define __NR_ugetrlimit 191 ++#endif ++#ifndef __NR_stat64 ++#define __NR_stat64 195 ++#endif ++#ifndef __NR_fstat64 ++#define __NR_fstat64 197 ++#endif ++#ifndef __NR_setresuid32 ++#define __NR_setresuid32 208 ++#define __NR_getresuid32 209 ++#define __NR_setresgid32 210 ++#define __NR_getresgid32 211 ++#endif ++#ifndef __NR_setfsuid32 ++#define __NR_setfsuid32 215 ++#define __NR_setfsgid32 216 ++#endif ++#ifndef __NR_getdents64 ++#define __NR_getdents64 220 ++#endif ++#ifndef __NR_gettid ++#define __NR_gettid 224 ++#endif ++#ifndef __NR_readahead ++#define __NR_readahead 225 ++#endif ++#ifndef __NR_setxattr ++#define __NR_setxattr 226 ++#endif ++#ifndef __NR_lsetxattr ++#define __NR_lsetxattr 227 ++#endif ++#ifndef __NR_getxattr ++#define __NR_getxattr 229 ++#endif ++#ifndef __NR_lgetxattr ++#define __NR_lgetxattr 230 ++#endif ++#ifndef __NR_listxattr ++#define __NR_listxattr 232 ++#endif ++#ifndef __NR_llistxattr ++#define __NR_llistxattr 233 ++#endif ++#ifndef __NR_tkill ++#define __NR_tkill 238 ++#endif ++#ifndef __NR_futex ++#define __NR_futex 240 ++#endif ++#ifndef __NR_sched_setaffinity ++#define __NR_sched_setaffinity 241 ++#define __NR_sched_getaffinity 242 ++#endif ++#ifndef __NR_set_tid_address ++#define __NR_set_tid_address 258 ++#endif ++#ifndef __NR_clock_gettime ++#define __NR_clock_gettime 265 ++#endif ++#ifndef __NR_clock_getres ++#define __NR_clock_getres 266 ++#endif ++#ifndef __NR_statfs64 ++#define __NR_statfs64 268 ++#endif ++#ifndef __NR_fstatfs64 ++#define __NR_fstatfs64 269 ++#endif ++#ifndef __NR_fadvise64_64 ++#define __NR_fadvise64_64 272 ++#endif ++#ifndef __NR_ioprio_set ++#define __NR_ioprio_set 289 ++#endif ++#ifndef __NR_ioprio_get ++#define __NR_ioprio_get 290 ++#endif ++#ifndef __NR_openat ++#define __NR_openat 295 ++#endif ++#ifndef __NR_fstatat64 ++#define __NR_fstatat64 300 ++#endif ++#ifndef __NR_unlinkat ++#define __NR_unlinkat 301 ++#endif ++#ifndef __NR_move_pages ++#define __NR_move_pages 317 ++#endif ++#ifndef __NR_getcpu ++#define __NR_getcpu 318 ++#endif ++#ifndef __NR_fallocate ++#define __NR_fallocate 324 ++#endif ++#ifndef __NR_getrandom ++#define __NR_getrandom 355 ++#endif ++/* End of i386 definitions */ ++#elif defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) ++#ifndef __NR_setresuid ++#define __NR_setresuid (__NR_SYSCALL_BASE + 164) ++#define __NR_getresuid (__NR_SYSCALL_BASE + 165) ++#define __NR_setresgid (__NR_SYSCALL_BASE + 170) ++#define __NR_getresgid (__NR_SYSCALL_BASE + 171) ++#endif ++#ifndef __NR_rt_sigaction ++#define __NR_rt_sigreturn (__NR_SYSCALL_BASE + 173) ++#define __NR_rt_sigaction (__NR_SYSCALL_BASE + 174) ++#define __NR_rt_sigprocmask (__NR_SYSCALL_BASE + 175) ++#define __NR_rt_sigpending (__NR_SYSCALL_BASE + 176) ++#define __NR_rt_sigsuspend (__NR_SYSCALL_BASE + 179) ++#endif ++#ifndef __NR_pread64 ++#define __NR_pread64 (__NR_SYSCALL_BASE + 180) ++#endif ++#ifndef __NR_pwrite64 ++#define __NR_pwrite64 (__NR_SYSCALL_BASE + 181) ++#endif ++#ifndef __NR_ugetrlimit ++#define __NR_ugetrlimit (__NR_SYSCALL_BASE + 191) ++#endif ++#ifndef __NR_stat64 ++#define __NR_stat64 (__NR_SYSCALL_BASE + 195) ++#endif ++#ifndef __NR_fstat64 ++#define __NR_fstat64 (__NR_SYSCALL_BASE + 197) ++#endif ++#ifndef __NR_setresuid32 ++#define __NR_setresuid32 (__NR_SYSCALL_BASE + 208) ++#define __NR_getresuid32 (__NR_SYSCALL_BASE + 209) ++#define __NR_setresgid32 (__NR_SYSCALL_BASE + 210) ++#define __NR_getresgid32 (__NR_SYSCALL_BASE + 211) ++#endif ++#ifndef __NR_setfsuid32 ++#define __NR_setfsuid32 (__NR_SYSCALL_BASE + 215) ++#define __NR_setfsgid32 (__NR_SYSCALL_BASE + 216) ++#endif ++#ifndef __NR_getdents64 ++#define __NR_getdents64 (__NR_SYSCALL_BASE + 217) ++#endif ++#ifndef __NR_gettid ++#define __NR_gettid (__NR_SYSCALL_BASE + 224) ++#endif ++#ifndef __NR_readahead ++#define __NR_readahead (__NR_SYSCALL_BASE + 225) ++#endif ++#ifndef __NR_setxattr ++#define __NR_setxattr (__NR_SYSCALL_BASE + 226) ++#endif ++#ifndef __NR_lsetxattr ++#define __NR_lsetxattr (__NR_SYSCALL_BASE + 227) ++#endif ++#ifndef __NR_getxattr ++#define __NR_getxattr (__NR_SYSCALL_BASE + 229) ++#endif ++#ifndef __NR_lgetxattr ++#define __NR_lgetxattr (__NR_SYSCALL_BASE + 230) ++#endif ++#ifndef __NR_listxattr ++#define __NR_listxattr (__NR_SYSCALL_BASE + 232) ++#endif ++#ifndef __NR_llistxattr ++#define __NR_llistxattr (__NR_SYSCALL_BASE + 233) ++#endif ++#ifndef __NR_tkill ++#define __NR_tkill (__NR_SYSCALL_BASE + 238) ++#endif ++#ifndef __NR_futex ++#define __NR_futex (__NR_SYSCALL_BASE + 240) ++#endif ++#ifndef __NR_sched_setaffinity ++#define __NR_sched_setaffinity (__NR_SYSCALL_BASE + 241) ++#define __NR_sched_getaffinity (__NR_SYSCALL_BASE + 242) ++#endif ++#ifndef __NR_set_tid_address ++#define __NR_set_tid_address (__NR_SYSCALL_BASE + 256) ++#endif ++#ifndef __NR_clock_gettime ++#define __NR_clock_gettime (__NR_SYSCALL_BASE + 263) ++#endif ++#ifndef __NR_clock_getres ++#define __NR_clock_getres (__NR_SYSCALL_BASE + 264) ++#endif ++#ifndef __NR_statfs64 ++#define __NR_statfs64 (__NR_SYSCALL_BASE + 266) ++#endif ++#ifndef __NR_fstatfs64 ++#define __NR_fstatfs64 (__NR_SYSCALL_BASE + 267) ++#endif ++#ifndef __NR_ioprio_set ++#define __NR_ioprio_set (__NR_SYSCALL_BASE + 314) ++#endif ++#ifndef __NR_ioprio_get ++#define __NR_ioprio_get (__NR_SYSCALL_BASE + 315) ++#endif ++#ifndef __NR_fstatat64 ++#define __NR_fstatat64 (__NR_SYSCALL_BASE + 327) ++#endif ++#ifndef __NR_move_pages ++#define __NR_move_pages (__NR_SYSCALL_BASE + 344) ++#endif ++#ifndef __NR_getcpu ++#define __NR_getcpu (__NR_SYSCALL_BASE + 345) ++#endif ++#ifndef __NR_getrandom ++#define __NR_getrandom (__NR_SYSCALL_BASE + 384) ++#endif ++/* End of ARM 3/EABI definitions */ ++#elif defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64) ++#ifndef __NR_setxattr ++#define __NR_setxattr 5 ++#endif ++#ifndef __NR_lsetxattr ++#define __NR_lsetxattr 6 ++#endif ++#ifndef __NR_getxattr ++#define __NR_getxattr 8 ++#endif ++#ifndef __NR_lgetxattr ++#define __NR_lgetxattr 9 ++#endif ++#ifndef __NR_listxattr ++#define __NR_listxattr 11 ++#endif ++#ifndef __NR_llistxattr ++#define __NR_llistxattr 12 ++#endif ++#ifndef __NR_ioprio_set ++#define __NR_ioprio_set 30 ++#endif ++#ifndef __NR_ioprio_get ++#define __NR_ioprio_get 31 ++#endif ++#ifndef __NR_unlinkat ++#define __NR_unlinkat 35 ++#endif ++#ifndef __NR_fallocate ++#define __NR_fallocate 47 ++#endif ++#ifndef __NR_openat ++#define __NR_openat 56 ++#endif ++#ifndef __NR_quotactl ++#define __NR_quotactl 60 ++#endif ++#ifndef __NR_getdents64 ++#define __NR_getdents64 61 ++#endif ++#ifndef __NR_getdents ++// when getdents is not available, getdents64 is used for both. ++#define __NR_getdents __NR_getdents64 ++#endif ++#ifndef __NR_pread64 ++#define __NR_pread64 67 ++#endif ++#ifndef __NR_pwrite64 ++#define __NR_pwrite64 68 ++#endif ++#ifndef __NR_ppoll ++#define __NR_ppoll 73 ++#endif ++#ifndef __NR_readlinkat ++#define __NR_readlinkat 78 ++#endif ++#if !defined(__loongarch_lp64) ++#ifndef __NR_newfstatat ++#define __NR_newfstatat 79 ++#endif ++#endif ++#ifndef __NR_set_tid_address ++#define __NR_set_tid_address 96 ++#endif ++#ifndef __NR_futex ++#define __NR_futex 98 ++#endif ++#ifndef __NR_clock_gettime ++#define __NR_clock_gettime 113 ++#endif ++#ifndef __NR_clock_getres ++#define __NR_clock_getres 114 ++#endif ++#ifndef __NR_sched_setaffinity ++#define __NR_sched_setaffinity 122 ++#define __NR_sched_getaffinity 123 ++#endif ++#ifndef __NR_tkill ++#define __NR_tkill 130 ++#endif ++#ifndef __NR_setresuid ++#define __NR_setresuid 147 ++#define __NR_getresuid 148 ++#define __NR_setresgid 149 ++#define __NR_getresgid 150 ++#endif ++#ifndef __NR_gettid ++#define __NR_gettid 178 ++#endif ++#ifndef __NR_readahead ++#define __NR_readahead 213 ++#endif ++#ifndef __NR_fadvise64 ++#define __NR_fadvise64 223 ++#endif ++#ifndef __NR_move_pages ++#define __NR_move_pages 239 ++#endif ++#ifndef __NR_getrandom ++#define __NR_getrandom 278 ++#endif ++#ifndef __NR_statx ++#define __NR_statx 291 ++#endif ++#elif defined(__x86_64__) ++#ifndef __NR_pread64 ++#define __NR_pread64 17 ++#endif ++#ifndef __NR_pwrite64 ++#define __NR_pwrite64 18 ++#endif ++#ifndef __NR_setresuid ++#define __NR_setresuid 117 ++#define __NR_getresuid 118 ++#define __NR_setresgid 119 ++#define __NR_getresgid 120 ++#endif ++#ifndef __NR_quotactl ++#define __NR_quotactl 179 ++#endif ++#ifndef __NR_gettid ++#define __NR_gettid 186 ++#endif ++#ifndef __NR_readahead ++#define __NR_readahead 187 ++#endif ++#ifndef __NR_setxattr ++#define __NR_setxattr 188 ++#endif ++#ifndef __NR_lsetxattr ++#define __NR_lsetxattr 189 ++#endif ++#ifndef __NR_getxattr ++#define __NR_getxattr 191 ++#endif ++#ifndef __NR_lgetxattr ++#define __NR_lgetxattr 192 ++#endif ++#ifndef __NR_listxattr ++#define __NR_listxattr 194 ++#endif ++#ifndef __NR_llistxattr ++#define __NR_llistxattr 195 ++#endif ++#ifndef __NR_tkill ++#define __NR_tkill 200 ++#endif ++#ifndef __NR_futex ++#define __NR_futex 202 ++#endif ++#ifndef __NR_sched_setaffinity ++#define __NR_sched_setaffinity 203 ++#define __NR_sched_getaffinity 204 ++#endif ++#ifndef __NR_getdents64 ++#define __NR_getdents64 217 ++#endif ++#ifndef __NR_getdents ++// when getdents is not available, getdents64 is used for both. ++#define __NR_getdents __NR_getdents64 ++#endif ++#ifndef __NR_set_tid_address ++#define __NR_set_tid_address 218 ++#endif ++#ifndef __NR_fadvise64 ++#define __NR_fadvise64 221 ++#endif ++#ifndef __NR_clock_gettime ++#define __NR_clock_gettime 228 ++#endif ++#ifndef __NR_clock_getres ++#define __NR_clock_getres 229 ++#endif ++#ifndef __NR_ioprio_set ++#define __NR_ioprio_set 251 ++#endif ++#ifndef __NR_ioprio_get ++#define __NR_ioprio_get 252 ++#endif ++#ifndef __NR_openat ++#define __NR_openat 257 ++#endif ++#ifndef __NR_newfstatat ++#define __NR_newfstatat 262 ++#endif ++#ifndef __NR_unlinkat ++#define __NR_unlinkat 263 ++#endif ++#ifndef __NR_move_pages ++#define __NR_move_pages 279 ++#endif ++#ifndef __NR_fallocate ++#define __NR_fallocate 285 ++#endif ++#ifndef __NR_getrandom ++#define __NR_getrandom 318 ++#endif ++/* End of x86-64 definitions */ ++#elif defined(__mips__) ++#if _MIPS_SIM == _MIPS_SIM_ABI32 ++#ifndef __NR_setresuid ++#define __NR_setresuid (__NR_Linux + 185) ++#define __NR_getresuid (__NR_Linux + 186) ++#define __NR_setresgid (__NR_Linux + 190) ++#define __NR_getresgid (__NR_Linux + 191) ++#endif ++#ifndef __NR_rt_sigaction ++#define __NR_rt_sigreturn (__NR_Linux + 193) ++#define __NR_rt_sigaction (__NR_Linux + 194) ++#define __NR_rt_sigprocmask (__NR_Linux + 195) ++#define __NR_rt_sigpending (__NR_Linux + 196) ++#define __NR_rt_sigsuspend (__NR_Linux + 199) ++#endif ++#ifndef __NR_pread64 ++#define __NR_pread64 (__NR_Linux + 200) ++#endif ++#ifndef __NR_pwrite64 ++#define __NR_pwrite64 (__NR_Linux + 201) ++#endif ++#ifndef __NR_stat64 ++#define __NR_stat64 (__NR_Linux + 213) ++#endif ++#ifndef __NR_fstat64 ++#define __NR_fstat64 (__NR_Linux + 215) ++#endif ++#ifndef __NR_getdents64 ++#define __NR_getdents64 (__NR_Linux + 219) ++#endif ++#ifndef __NR_gettid ++#define __NR_gettid (__NR_Linux + 222) ++#endif ++#ifndef __NR_readahead ++#define __NR_readahead (__NR_Linux + 223) ++#endif ++#ifndef __NR_setxattr ++#define __NR_setxattr (__NR_Linux + 224) ++#endif ++#ifndef __NR_lsetxattr ++#define __NR_lsetxattr (__NR_Linux + 225) ++#endif ++#ifndef __NR_getxattr ++#define __NR_getxattr (__NR_Linux + 227) ++#endif ++#ifndef __NR_lgetxattr ++#define __NR_lgetxattr (__NR_Linux + 228) ++#endif ++#ifndef __NR_listxattr ++#define __NR_listxattr (__NR_Linux + 230) ++#endif ++#ifndef __NR_llistxattr ++#define __NR_llistxattr (__NR_Linux + 231) ++#endif ++#ifndef __NR_tkill ++#define __NR_tkill (__NR_Linux + 236) ++#endif ++#ifndef __NR_futex ++#define __NR_futex (__NR_Linux + 238) ++#endif ++#ifndef __NR_sched_setaffinity ++#define __NR_sched_setaffinity (__NR_Linux + 239) ++#define __NR_sched_getaffinity (__NR_Linux + 240) ++#endif ++#ifndef __NR_set_tid_address ++#define __NR_set_tid_address (__NR_Linux + 252) ++#endif ++#ifndef __NR_statfs64 ++#define __NR_statfs64 (__NR_Linux + 255) ++#endif ++#ifndef __NR_fstatfs64 ++#define __NR_fstatfs64 (__NR_Linux + 256) ++#endif ++#ifndef __NR_clock_gettime ++#define __NR_clock_gettime (__NR_Linux + 263) ++#endif ++#ifndef __NR_clock_getres ++#define __NR_clock_getres (__NR_Linux + 264) ++#endif ++#ifndef __NR_openat ++#define __NR_openat (__NR_Linux + 288) ++#endif ++#ifndef __NR_fstatat ++#define __NR_fstatat (__NR_Linux + 293) ++#endif ++#ifndef __NR_unlinkat ++#define __NR_unlinkat (__NR_Linux + 294) ++#endif ++#ifndef __NR_move_pages ++#define __NR_move_pages (__NR_Linux + 308) ++#endif ++#ifndef __NR_getcpu ++#define __NR_getcpu (__NR_Linux + 312) ++#endif ++#ifndef __NR_ioprio_set ++#define __NR_ioprio_set (__NR_Linux + 314) ++#endif ++#ifndef __NR_ioprio_get ++#define __NR_ioprio_get (__NR_Linux + 315) ++#endif ++#ifndef __NR_getrandom ++#define __NR_getrandom (__NR_Linux + 353) ++#endif ++/* End of MIPS (old 32bit API) definitions */ ++#elif _MIPS_SIM == _MIPS_SIM_ABI64 ++#ifndef __NR_pread64 ++#define __NR_pread64 (__NR_Linux + 16) ++#endif ++#ifndef __NR_pwrite64 ++#define __NR_pwrite64 (__NR_Linux + 17) ++#endif ++#ifndef __NR_setresuid ++#define __NR_setresuid (__NR_Linux + 115) ++#define __NR_getresuid (__NR_Linux + 116) ++#define __NR_setresgid (__NR_Linux + 117) ++#define __NR_getresgid (__NR_Linux + 118) ++#endif ++#ifndef __NR_gettid ++#define __NR_gettid (__NR_Linux + 178) ++#endif ++#ifndef __NR_readahead ++#define __NR_readahead (__NR_Linux + 179) ++#endif ++#ifndef __NR_setxattr ++#define __NR_setxattr (__NR_Linux + 180) ++#endif ++#ifndef __NR_lsetxattr ++#define __NR_lsetxattr (__NR_Linux + 181) ++#endif ++#ifndef __NR_getxattr ++#define __NR_getxattr (__NR_Linux + 183) ++#endif ++#ifndef __NR_lgetxattr ++#define __NR_lgetxattr (__NR_Linux + 184) ++#endif ++#ifndef __NR_listxattr ++#define __NR_listxattr (__NR_Linux + 186) ++#endif ++#ifndef __NR_llistxattr ++#define __NR_llistxattr (__NR_Linux + 187) ++#endif ++#ifndef __NR_tkill ++#define __NR_tkill (__NR_Linux + 192) ++#endif ++#ifndef __NR_futex ++#define __NR_futex (__NR_Linux + 194) ++#endif ++#ifndef __NR_sched_setaffinity ++#define __NR_sched_setaffinity (__NR_Linux + 195) ++#define __NR_sched_getaffinity (__NR_Linux + 196) ++#endif ++#ifndef __NR_set_tid_address ++#define __NR_set_tid_address (__NR_Linux + 212) ++#endif ++#ifndef __NR_clock_gettime ++#define __NR_clock_gettime (__NR_Linux + 222) ++#endif ++#ifndef __NR_clock_getres ++#define __NR_clock_getres (__NR_Linux + 223) ++#endif ++#ifndef __NR_openat ++#define __NR_openat (__NR_Linux + 247) ++#endif ++#ifndef __NR_fstatat ++#define __NR_fstatat (__NR_Linux + 252) ++#endif ++#ifndef __NR_unlinkat ++#define __NR_unlinkat (__NR_Linux + 253) ++#endif ++#ifndef __NR_move_pages ++#define __NR_move_pages (__NR_Linux + 267) ++#endif ++#ifndef __NR_getcpu ++#define __NR_getcpu (__NR_Linux + 271) ++#endif ++#ifndef __NR_ioprio_set ++#define __NR_ioprio_set (__NR_Linux + 273) ++#endif ++#ifndef __NR_ioprio_get ++#define __NR_ioprio_get (__NR_Linux + 274) ++#endif ++#ifndef __NR_getrandom ++#define __NR_getrandom (__NR_Linux + 313) ++#endif ++/* End of MIPS (64bit API) definitions */ ++#else ++#ifndef __NR_setresuid ++#define __NR_setresuid (__NR_Linux + 115) ++#define __NR_getresuid (__NR_Linux + 116) ++#define __NR_setresgid (__NR_Linux + 117) ++#define __NR_getresgid (__NR_Linux + 118) ++#endif ++#ifndef __NR_gettid ++#define __NR_gettid (__NR_Linux + 178) ++#endif ++#ifndef __NR_readahead ++#define __NR_readahead (__NR_Linux + 179) ++#endif ++#ifndef __NR_setxattr ++#define __NR_setxattr (__NR_Linux + 180) ++#endif ++#ifndef __NR_lsetxattr ++#define __NR_lsetxattr (__NR_Linux + 181) ++#endif ++#ifndef __NR_getxattr ++#define __NR_getxattr (__NR_Linux + 183) ++#endif ++#ifndef __NR_lgetxattr ++#define __NR_lgetxattr (__NR_Linux + 184) ++#endif ++#ifndef __NR_listxattr ++#define __NR_listxattr (__NR_Linux + 186) ++#endif ++#ifndef __NR_llistxattr ++#define __NR_llistxattr (__NR_Linux + 187) ++#endif ++#ifndef __NR_tkill ++#define __NR_tkill (__NR_Linux + 192) ++#endif ++#ifndef __NR_futex ++#define __NR_futex (__NR_Linux + 194) ++#endif ++#ifndef __NR_sched_setaffinity ++#define __NR_sched_setaffinity (__NR_Linux + 195) ++#define __NR_sched_getaffinity (__NR_Linux + 196) ++#endif ++#ifndef __NR_set_tid_address ++#define __NR_set_tid_address (__NR_Linux + 213) ++#endif ++#ifndef __NR_statfs64 ++#define __NR_statfs64 (__NR_Linux + 217) ++#endif ++#ifndef __NR_fstatfs64 ++#define __NR_fstatfs64 (__NR_Linux + 218) ++#endif ++#ifndef __NR_clock_gettime ++#define __NR_clock_gettime (__NR_Linux + 226) ++#endif ++#ifndef __NR_clock_getres ++#define __NR_clock_getres (__NR_Linux + 227) ++#endif ++#ifndef __NR_openat ++#define __NR_openat (__NR_Linux + 251) ++#endif ++#ifndef __NR_fstatat ++#define __NR_fstatat (__NR_Linux + 256) ++#endif ++#ifndef __NR_unlinkat ++#define __NR_unlinkat (__NR_Linux + 257) ++#endif ++#ifndef __NR_move_pages ++#define __NR_move_pages (__NR_Linux + 271) ++#endif ++#ifndef __NR_getcpu ++#define __NR_getcpu (__NR_Linux + 275) ++#endif ++#ifndef __NR_ioprio_set ++#define __NR_ioprio_set (__NR_Linux + 277) ++#endif ++#ifndef __NR_ioprio_get ++#define __NR_ioprio_get (__NR_Linux + 278) ++#endif ++/* End of MIPS (new 32bit API) definitions */ ++#endif ++/* End of MIPS definitions */ ++#elif defined(__PPC__) ++#ifndef __NR_setfsuid ++#define __NR_setfsuid 138 ++#define __NR_setfsgid 139 ++#endif ++#ifndef __NR_setresuid ++#define __NR_setresuid 164 ++#define __NR_getresuid 165 ++#define __NR_setresgid 169 ++#define __NR_getresgid 170 ++#endif ++#ifndef __NR_rt_sigaction ++#define __NR_rt_sigreturn 172 ++#define __NR_rt_sigaction 173 ++#define __NR_rt_sigprocmask 174 ++#define __NR_rt_sigpending 175 ++#define __NR_rt_sigsuspend 178 ++#endif ++#ifndef __NR_pread64 ++#define __NR_pread64 179 ++#endif ++#ifndef __NR_pwrite64 ++#define __NR_pwrite64 180 ++#endif ++#ifndef __NR_ugetrlimit ++#define __NR_ugetrlimit 190 ++#endif ++#ifndef __NR_readahead ++#define __NR_readahead 191 ++#endif ++#ifndef __NR_stat64 ++#define __NR_stat64 195 ++#endif ++#ifndef __NR_fstat64 ++#define __NR_fstat64 197 ++#endif ++#ifndef __NR_getdents64 ++#define __NR_getdents64 202 ++#endif ++#ifndef __NR_gettid ++#define __NR_gettid 207 ++#endif ++#ifndef __NR_tkill ++#define __NR_tkill 208 ++#endif ++#ifndef __NR_setxattr ++#define __NR_setxattr 209 ++#endif ++#ifndef __NR_lsetxattr ++#define __NR_lsetxattr 210 ++#endif ++#ifndef __NR_getxattr ++#define __NR_getxattr 212 ++#endif ++#ifndef __NR_lgetxattr ++#define __NR_lgetxattr 213 ++#endif ++#ifndef __NR_listxattr ++#define __NR_listxattr 215 ++#endif ++#ifndef __NR_llistxattr ++#define __NR_llistxattr 216 ++#endif ++#ifndef __NR_futex ++#define __NR_futex 221 ++#endif ++#ifndef __NR_sched_setaffinity ++#define __NR_sched_setaffinity 222 ++#define __NR_sched_getaffinity 223 ++#endif ++#ifndef __NR_set_tid_address ++#define __NR_set_tid_address 232 ++#endif ++#ifndef __NR_clock_gettime ++#define __NR_clock_gettime 246 ++#endif ++#ifndef __NR_clock_getres ++#define __NR_clock_getres 247 ++#endif ++#ifndef __NR_statfs64 ++#define __NR_statfs64 252 ++#endif ++#ifndef __NR_fstatfs64 ++#define __NR_fstatfs64 253 ++#endif ++#ifndef __NR_fadvise64_64 ++#define __NR_fadvise64_64 254 ++#endif ++#ifndef __NR_ioprio_set ++#define __NR_ioprio_set 273 ++#endif ++#ifndef __NR_ioprio_get ++#define __NR_ioprio_get 274 ++#endif ++#ifndef __NR_openat ++#define __NR_openat 286 ++#endif ++#ifndef __NR_fstatat64 ++#define __NR_fstatat64 291 ++#endif ++#ifndef __NR_unlinkat ++#define __NR_unlinkat 292 ++#endif ++#ifndef __NR_move_pages ++#define __NR_move_pages 301 ++#endif ++#ifndef __NR_getcpu ++#define __NR_getcpu 302 ++#endif ++/* End of powerpc definitions */ ++#elif defined(__s390__) ++#ifndef __NR_quotactl ++#define __NR_quotactl 131 ++#endif ++#ifndef __NR_rt_sigreturn ++#define __NR_rt_sigreturn 173 ++#endif ++#ifndef __NR_rt_sigaction ++#define __NR_rt_sigaction 174 ++#endif ++#ifndef __NR_rt_sigprocmask ++#define __NR_rt_sigprocmask 175 ++#endif ++#ifndef __NR_rt_sigpending ++#define __NR_rt_sigpending 176 ++#endif ++#ifndef __NR_rt_sigsuspend ++#define __NR_rt_sigsuspend 179 ++#endif ++#ifndef __NR_pread64 ++#define __NR_pread64 180 ++#endif ++#ifndef __NR_pwrite64 ++#define __NR_pwrite64 181 ++#endif ++#ifndef __NR_getdents64 ++#define __NR_getdents64 220 ++#endif ++#ifndef __NR_readahead ++#define __NR_readahead 222 ++#endif ++#ifndef __NR_setxattr ++#define __NR_setxattr 224 ++#endif ++#ifndef __NR_lsetxattr ++#define __NR_lsetxattr 225 ++#endif ++#ifndef __NR_getxattr ++#define __NR_getxattr 227 ++#endif ++#ifndef __NR_lgetxattr ++#define __NR_lgetxattr 228 ++#endif ++#ifndef __NR_listxattr ++#define __NR_listxattr 230 ++#endif ++#ifndef __NR_llistxattr ++#define __NR_llistxattr 231 ++#endif ++#ifndef __NR_gettid ++#define __NR_gettid 236 ++#endif ++#ifndef __NR_tkill ++#define __NR_tkill 237 ++#endif ++#ifndef __NR_futex ++#define __NR_futex 238 ++#endif ++#ifndef __NR_sched_setaffinity ++#define __NR_sched_setaffinity 239 ++#endif ++#ifndef __NR_sched_getaffinity ++#define __NR_sched_getaffinity 240 ++#endif ++#ifndef __NR_set_tid_address ++#define __NR_set_tid_address 252 ++#endif ++#ifndef __NR_clock_gettime ++#define __NR_clock_gettime 260 ++#endif ++#ifndef __NR_clock_getres ++#define __NR_clock_getres 261 ++#endif ++#ifndef __NR_statfs64 ++#define __NR_statfs64 265 ++#endif ++#ifndef __NR_fstatfs64 ++#define __NR_fstatfs64 266 ++#endif ++#ifndef __NR_ioprio_set ++#define __NR_ioprio_set 282 ++#endif ++#ifndef __NR_ioprio_get ++#define __NR_ioprio_get 283 ++#endif ++#ifndef __NR_openat ++#define __NR_openat 288 ++#endif ++#ifndef __NR_unlinkat ++#define __NR_unlinkat 294 ++#endif ++#ifndef __NR_move_pages ++#define __NR_move_pages 310 ++#endif ++#ifndef __NR_getcpu ++#define __NR_getcpu 311 ++#endif ++#ifndef __NR_fallocate ++#define __NR_fallocate 314 ++#endif ++/* Some syscalls are named/numbered differently between s390 and s390x. */ ++#ifdef __s390x__ ++# ifndef __NR_getrlimit ++# define __NR_getrlimit 191 ++# endif ++# ifndef __NR_setresuid ++# define __NR_setresuid 208 ++# endif ++# ifndef __NR_getresuid ++# define __NR_getresuid 209 ++# endif ++# ifndef __NR_setresgid ++# define __NR_setresgid 210 ++# endif ++# ifndef __NR_getresgid ++# define __NR_getresgid 211 ++# endif ++# ifndef __NR_setfsuid ++# define __NR_setfsuid 215 ++# endif ++# ifndef __NR_setfsgid ++# define __NR_setfsgid 216 ++# endif ++# ifndef __NR_fadvise64 ++# define __NR_fadvise64 253 ++# endif ++# ifndef __NR_newfstatat ++# define __NR_newfstatat 293 ++# endif ++#else /* __s390x__ */ ++# ifndef __NR_getrlimit ++# define __NR_getrlimit 76 ++# endif ++# ifndef __NR_setfsuid ++# define __NR_setfsuid 138 ++# endif ++# ifndef __NR_setfsgid ++# define __NR_setfsgid 139 ++# endif ++# ifndef __NR_setresuid ++# define __NR_setresuid 164 ++# endif ++# ifndef __NR_getresuid ++# define __NR_getresuid 165 ++# endif ++# ifndef __NR_setresgid ++# define __NR_setresgid 170 ++# endif ++# ifndef __NR_getresgid ++# define __NR_getresgid 171 ++# endif ++# ifndef __NR_ugetrlimit ++# define __NR_ugetrlimit 191 ++# endif ++# ifndef __NR_mmap2 ++# define __NR_mmap2 192 ++# endif ++# ifndef __NR_setresuid32 ++# define __NR_setresuid32 208 ++# endif ++# ifndef __NR_getresuid32 ++# define __NR_getresuid32 209 ++# endif ++# ifndef __NR_setresgid32 ++# define __NR_setresgid32 210 ++# endif ++# ifndef __NR_getresgid32 ++# define __NR_getresgid32 211 ++# endif ++# ifndef __NR_setfsuid32 ++# define __NR_setfsuid32 215 ++# endif ++# ifndef __NR_setfsgid32 ++# define __NR_setfsgid32 216 ++# endif ++# ifndef __NR_fadvise64_64 ++# define __NR_fadvise64_64 264 ++# endif ++# ifndef __NR_fstatat64 ++# define __NR_fstatat64 293 ++# endif ++#endif /* __s390__ */ ++/* End of s390/s390x definitions */ ++#endif ++ ++ ++/* After forking, we must make sure to only call system calls. */ ++#if defined(__BOUNDED_POINTERS__) ++ #error "Need to port invocations of syscalls for bounded ptrs" ++#else ++ /* The core dumper and the thread lister get executed after threads ++ * have been suspended. As a consequence, we cannot call any functions ++ * that acquire locks. Unfortunately, libc wraps most system calls ++ * (e.g. in order to implement pthread_atfork, and to make calls ++ * cancellable), which means we cannot call these functions. Instead, ++ * we have to call syscall() directly. ++ */ ++ #undef LSS_ERRNO ++ #ifdef SYS_ERRNO ++ /* Allow the including file to override the location of errno. This can ++ * be useful when using clone() with the CLONE_VM option. ++ */ ++ #define LSS_ERRNO SYS_ERRNO ++ #else ++ #define LSS_ERRNO errno ++ #endif ++ ++ #undef LSS_INLINE ++ #ifdef SYS_INLINE ++ #define LSS_INLINE SYS_INLINE ++ #else ++ #define LSS_INLINE static inline ++ #endif ++ ++ /* Allow the including file to override the prefix used for all new ++ * system calls. By default, it will be set to "sys_". ++ */ ++ #undef LSS_NAME ++ #ifndef SYS_PREFIX ++ #define LSS_NAME(name) sys_##name ++ #elif defined(SYS_PREFIX) && SYS_PREFIX < 0 ++ #define LSS_NAME(name) name ++ #elif defined(SYS_PREFIX) && SYS_PREFIX == 0 ++ #define LSS_NAME(name) sys0_##name ++ #elif defined(SYS_PREFIX) && SYS_PREFIX == 1 ++ #define LSS_NAME(name) sys1_##name ++ #elif defined(SYS_PREFIX) && SYS_PREFIX == 2 ++ #define LSS_NAME(name) sys2_##name ++ #elif defined(SYS_PREFIX) && SYS_PREFIX == 3 ++ #define LSS_NAME(name) sys3_##name ++ #elif defined(SYS_PREFIX) && SYS_PREFIX == 4 ++ #define LSS_NAME(name) sys4_##name ++ #elif defined(SYS_PREFIX) && SYS_PREFIX == 5 ++ #define LSS_NAME(name) sys5_##name ++ #elif defined(SYS_PREFIX) && SYS_PREFIX == 6 ++ #define LSS_NAME(name) sys6_##name ++ #elif defined(SYS_PREFIX) && SYS_PREFIX == 7 ++ #define LSS_NAME(name) sys7_##name ++ #elif defined(SYS_PREFIX) && SYS_PREFIX == 8 ++ #define LSS_NAME(name) sys8_##name ++ #elif defined(SYS_PREFIX) && SYS_PREFIX == 9 ++ #define LSS_NAME(name) sys9_##name ++ #endif ++ ++ #undef LSS_RETURN ++ #if defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) \ ++ || defined(__ARM_EABI__) || defined(__aarch64__) || defined(__s390__) \ ++ || defined(__e2k__) || defined(__riscv) || defined(__loongarch_lp64) ++ /* Failing system calls return a negative result in the range of ++ * -1..-4095. These are "errno" values with the sign inverted. ++ */ ++ #define LSS_RETURN(type, res) \ ++ do { \ ++ if ((unsigned long)(res) >= (unsigned long)(-4095)) { \ ++ LSS_ERRNO = (int)(-(res)); \ ++ res = -1; \ ++ } \ ++ return (type) (res); \ ++ } while (0) ++ #elif defined(__mips__) ++ /* On MIPS, failing system calls return -1, and set errno in a ++ * separate CPU register. ++ */ ++ #define LSS_RETURN(type, res, err) \ ++ do { \ ++ if (err) { \ ++ unsigned long __errnovalue = (res); \ ++ LSS_ERRNO = __errnovalue; \ ++ res = -1; \ ++ } \ ++ return (type) (res); \ ++ } while (0) ++ #elif defined(__PPC__) ++ /* On PPC, failing system calls return -1, and set errno in a ++ * separate CPU register. See linux/unistd.h. ++ */ ++ #define LSS_RETURN(type, res, err) \ ++ do { \ ++ if (err & 0x10000000 ) { \ ++ LSS_ERRNO = (res); \ ++ res = -1; \ ++ } \ ++ return (type) (res); \ ++ } while (0) ++ #endif ++ #if defined(__i386__) ++ /* In PIC mode (e.g. when building shared libraries), gcc for i386 ++ * reserves ebx. Unfortunately, most distribution ship with implementations ++ * of _syscallX() which clobber ebx. ++ * Also, most definitions of _syscallX() neglect to mark "memory" as being ++ * clobbered. This causes problems with compilers, that do a better job ++ * at optimizing across __asm__ calls. ++ * So, we just have to redefine all of the _syscallX() macros. ++ */ ++ #undef LSS_ENTRYPOINT ++ #ifdef SYS_SYSCALL_ENTRYPOINT ++ static inline void (**LSS_NAME(get_syscall_entrypoint)(void))(void) { ++ void (**entrypoint)(void); ++ asm volatile(".bss\n" ++ ".align 8\n" ++ ".globl " SYS_SYSCALL_ENTRYPOINT "\n" ++ ".common " SYS_SYSCALL_ENTRYPOINT ",8,8\n" ++ ".previous\n" ++ /* This logically does 'lea "SYS_SYSCALL_ENTRYPOINT", %0' */ ++ "call 0f\n" ++ "0:pop %0\n" ++ "add $_GLOBAL_OFFSET_TABLE_+[.-0b], %0\n" ++ "mov " SYS_SYSCALL_ENTRYPOINT "@GOT(%0), %0\n" ++ : "=r"(entrypoint)); ++ return entrypoint; ++ } ++ ++ #define LSS_ENTRYPOINT ".bss\n" \ ++ ".align 8\n" \ ++ ".globl " SYS_SYSCALL_ENTRYPOINT "\n" \ ++ ".common " SYS_SYSCALL_ENTRYPOINT ",8,8\n" \ ++ ".previous\n" \ ++ /* Check the SYS_SYSCALL_ENTRYPOINT vector */ \ ++ "push %%eax\n" \ ++ "call 10000f\n" \ ++ "10000:pop %%eax\n" \ ++ "add $_GLOBAL_OFFSET_TABLE_+[.-10000b], %%eax\n" \ ++ "mov " SYS_SYSCALL_ENTRYPOINT \ ++ "@GOT(%%eax), %%eax\n" \ ++ "mov 0(%%eax), %%eax\n" \ ++ "test %%eax, %%eax\n" \ ++ "jz 10002f\n" \ ++ "push %%eax\n" \ ++ "call 10001f\n" \ ++ "10001:pop %%eax\n" \ ++ "add $(10003f-10001b), %%eax\n" \ ++ "xchg 4(%%esp), %%eax\n" \ ++ "ret\n" \ ++ "10002:pop %%eax\n" \ ++ "int $0x80\n" \ ++ "10003:\n" ++ #else ++ #define LSS_ENTRYPOINT "int $0x80\n" ++ #endif ++ #undef LSS_BODY ++ #define LSS_BODY(type,args...) \ ++ long __res; \ ++ __asm__ __volatile__("push %%ebx\n" \ ++ "movl %2,%%ebx\n" \ ++ LSS_ENTRYPOINT \ ++ "pop %%ebx" \ ++ args \ ++ : "memory"); \ ++ LSS_RETURN(type,__res) ++ #undef _syscall0 ++ #define _syscall0(type,name) \ ++ type LSS_NAME(name)(void) { \ ++ long __res; \ ++ __asm__ volatile(LSS_ENTRYPOINT \ ++ : "=a" (__res) \ ++ : "0" (__NR_##name) \ ++ : "memory"); \ ++ LSS_RETURN(type,__res); \ ++ } ++ #undef _syscall1 ++ #define _syscall1(type,name,type1,arg1) \ ++ type LSS_NAME(name)(type1 arg1) { \ ++ LSS_BODY(type, \ ++ : "=a" (__res) \ ++ : "0" (__NR_##name), "ri" ((long)(arg1))); \ ++ } ++ #undef _syscall2 ++ #define _syscall2(type,name,type1,arg1,type2,arg2) \ ++ type LSS_NAME(name)(type1 arg1,type2 arg2) { \ ++ LSS_BODY(type, \ ++ : "=a" (__res) \ ++ : "0" (__NR_##name),"ri" ((long)(arg1)), "c" ((long)(arg2))); \ ++ } ++ #undef _syscall3 ++ #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ ++ type LSS_NAME(name)(type1 arg1,type2 arg2,type3 arg3) { \ ++ LSS_BODY(type, \ ++ : "=a" (__res) \ ++ : "0" (__NR_##name), "ri" ((long)(arg1)), "c" ((long)(arg2)), \ ++ "d" ((long)(arg3))); \ ++ } ++ #undef _syscall4 ++ #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ ++ LSS_BODY(type, \ ++ : "=a" (__res) \ ++ : "0" (__NR_##name), "ri" ((long)(arg1)), "c" ((long)(arg2)), \ ++ "d" ((long)(arg3)),"S" ((long)(arg4))); \ ++ } ++ #undef _syscall5 ++ #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5) { \ ++ long __res; \ ++ __asm__ __volatile__("push %%ebx\n" \ ++ "movl %2,%%ebx\n" \ ++ "movl %1,%%eax\n" \ ++ LSS_ENTRYPOINT \ ++ "pop %%ebx" \ ++ : "=a" (__res) \ ++ : "i" (__NR_##name), "ri" ((long)(arg1)), \ ++ "c" ((long)(arg2)), "d" ((long)(arg3)), \ ++ "S" ((long)(arg4)), "D" ((long)(arg5)) \ ++ : "memory"); \ ++ LSS_RETURN(type,__res); \ ++ } ++ #undef _syscall6 ++ #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5,type6,arg6) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5, type6 arg6) { \ ++ long __res; \ ++ struct { long __a1; long __a6; } __s = { (long)arg1, (long) arg6 }; \ ++ __asm__ __volatile__("push %%ebp\n" \ ++ "push %%ebx\n" \ ++ "movl 4(%2),%%ebp\n" \ ++ "movl 0(%2), %%ebx\n" \ ++ "movl %1,%%eax\n" \ ++ LSS_ENTRYPOINT \ ++ "pop %%ebx\n" \ ++ "pop %%ebp" \ ++ : "=a" (__res) \ ++ : "i" (__NR_##name), "0" ((long)(&__s)), \ ++ "c" ((long)(arg2)), "d" ((long)(arg3)), \ ++ "S" ((long)(arg4)), "D" ((long)(arg5)) \ ++ : "memory"); \ ++ LSS_RETURN(type,__res); \ ++ } ++ LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, ++ int flags, void *arg, int *parent_tidptr, ++ void *newtls, int *child_tidptr) { ++ long __res; ++ __asm__ __volatile__(/* if (fn == NULL) ++ * return -EINVAL; ++ */ ++ "movl %3,%%ecx\n" ++ "jecxz 1f\n" ++ ++ /* if (child_stack == NULL) ++ * return -EINVAL; ++ */ ++ "movl %4,%%ecx\n" ++ "jecxz 1f\n" ++ ++ /* Set up alignment of the child stack: ++ * child_stack = (child_stack & ~0xF) - 20; ++ */ ++ "andl $-16,%%ecx\n" ++ "subl $20,%%ecx\n" ++ ++ /* Push "arg" and "fn" onto the stack that will be ++ * used by the child. ++ */ ++ "movl %6,%%eax\n" ++ "movl %%eax,4(%%ecx)\n" ++ "movl %3,%%eax\n" ++ "movl %%eax,(%%ecx)\n" ++ ++ /* %eax = syscall(%eax = __NR_clone, ++ * %ebx = flags, ++ * %ecx = child_stack, ++ * %edx = parent_tidptr, ++ * %esi = newtls, ++ * %edi = child_tidptr) ++ * Also, make sure that %ebx gets preserved as it is ++ * used in PIC mode. ++ */ ++ "movl %8,%%esi\n" ++ "movl %7,%%edx\n" ++ "movl %5,%%eax\n" ++ "movl %9,%%edi\n" ++ "pushl %%ebx\n" ++ "movl %%eax,%%ebx\n" ++ "movl %2,%%eax\n" ++ LSS_ENTRYPOINT ++ ++ /* In the parent: restore %ebx ++ * In the child: move "fn" into %ebx ++ */ ++ "popl %%ebx\n" ++ ++ /* if (%eax != 0) ++ * return %eax; ++ */ ++ "test %%eax,%%eax\n" ++ "jnz 1f\n" ++ ++ /* In the child, now. Terminate frame pointer chain. ++ */ ++ "movl $0,%%ebp\n" ++ ++ /* Call "fn". "arg" is already on the stack. ++ */ ++ "call *%%ebx\n" ++ ++ /* Call _exit(%ebx). Unfortunately older versions ++ * of gcc restrict the number of arguments that can ++ * be passed to asm(). So, we need to hard-code the ++ * system call number. ++ */ ++ "movl %%eax,%%ebx\n" ++ "movl $1,%%eax\n" ++ LSS_ENTRYPOINT ++ ++ /* Return to parent. ++ */ ++ "1:\n" ++ : "=a" (__res) ++ : "0"(-EINVAL), "i"(__NR_clone), ++ "m"(fn), "m"(child_stack), "m"(flags), "m"(arg), ++ "m"(parent_tidptr), "m"(newtls), "m"(child_tidptr) ++ : "memory", "ecx", "edx", "esi", "edi"); ++ LSS_RETURN(int, __res); ++ } ++ ++ LSS_INLINE _syscall1(int, set_thread_area, void *, u) ++ LSS_INLINE _syscall1(int, get_thread_area, void *, u) ++ ++ LSS_INLINE void (*LSS_NAME(restore_rt)(void))(void) { ++ /* On i386, the kernel does not know how to return from a signal ++ * handler. Instead, it relies on user space to provide a ++ * restorer function that calls the {rt_,}sigreturn() system call. ++ * Unfortunately, we cannot just reference the glibc version of this ++ * function, as glibc goes out of its way to make it inaccessible. ++ */ ++ void (*res)(void); ++ __asm__ __volatile__("call 2f\n" ++ "0:.align 16\n" ++ "1:movl %1,%%eax\n" ++ LSS_ENTRYPOINT ++ "2:popl %0\n" ++ "addl $(1b-0b),%0\n" ++ : "=a" (res) ++ : "i" (__NR_rt_sigreturn)); ++ return res; ++ } ++ LSS_INLINE void (*LSS_NAME(restore)(void))(void) { ++ /* On i386, the kernel does not know how to return from a signal ++ * handler. Instead, it relies on user space to provide a ++ * restorer function that calls the {rt_,}sigreturn() system call. ++ * Unfortunately, we cannot just reference the glibc version of this ++ * function, as glibc goes out of its way to make it inaccessible. ++ */ ++ void (*res)(void); ++ __asm__ __volatile__("call 2f\n" ++ "0:.align 16\n" ++ "1:pop %%eax\n" ++ "movl %1,%%eax\n" ++ LSS_ENTRYPOINT ++ "2:popl %0\n" ++ "addl $(1b-0b),%0\n" ++ : "=a" (res) ++ : "i" (__NR_sigreturn)); ++ return res; ++ } ++ #elif defined(__x86_64__) ++ /* There are no known problems with any of the _syscallX() macros ++ * currently shipping for x86_64, but we still need to be able to define ++ * our own version so that we can override the location of the errno ++ * location (e.g. when using the clone() system call with the CLONE_VM ++ * option). ++ */ ++ #undef LSS_ENTRYPOINT ++ #ifdef SYS_SYSCALL_ENTRYPOINT ++ static inline void (**LSS_NAME(get_syscall_entrypoint)(void))(void) { ++ void (**entrypoint)(void); ++ asm volatile(".bss\n" ++ ".align 8\n" ++ ".globl " SYS_SYSCALL_ENTRYPOINT "\n" ++ ".common " SYS_SYSCALL_ENTRYPOINT ",8,8\n" ++ ".previous\n" ++ "mov " SYS_SYSCALL_ENTRYPOINT "@GOTPCREL(%%rip), %0\n" ++ : "=r"(entrypoint)); ++ return entrypoint; ++ } ++ ++ #define LSS_ENTRYPOINT \ ++ ".bss\n" \ ++ ".align 8\n" \ ++ ".globl " SYS_SYSCALL_ENTRYPOINT "\n" \ ++ ".common " SYS_SYSCALL_ENTRYPOINT ",8,8\n" \ ++ ".previous\n" \ ++ "mov " SYS_SYSCALL_ENTRYPOINT "@GOTPCREL(%%rip), %%rcx\n" \ ++ "mov 0(%%rcx), %%rcx\n" \ ++ "test %%rcx, %%rcx\n" \ ++ "jz 10001f\n" \ ++ "call *%%rcx\n" \ ++ "jmp 10002f\n" \ ++ "10001:syscall\n" \ ++ "10002:\n" ++ ++ #else ++ #define LSS_ENTRYPOINT "syscall\n" ++ #endif ++ ++ /* The x32 ABI has 32 bit longs, but the syscall interface is 64 bit. ++ * We need to explicitly cast to an unsigned 64 bit type to avoid implicit ++ * sign extension. We can't cast pointers directly because those are ++ * 32 bits, and gcc will dump ugly warnings about casting from a pointer ++ * to an integer of a different size. ++ */ ++ #undef LSS_SYSCALL_ARG ++ #define LSS_SYSCALL_ARG(a) ((uint64_t)(uintptr_t)(a)) ++ #undef _LSS_RETURN ++ #define _LSS_RETURN(type, res, cast) \ ++ do { \ ++ if ((uint64_t)(res) >= (uint64_t)(-4095)) { \ ++ LSS_ERRNO = (int)(-(res)); \ ++ res = -1; \ ++ } \ ++ return (type)(cast)(res); \ ++ } while (0) ++ #undef LSS_RETURN ++ #define LSS_RETURN(type, res) _LSS_RETURN(type, res, uintptr_t) ++ ++ #undef _LSS_BODY ++ #define _LSS_BODY(nr, type, name, cast, ...) \ ++ long long __res; \ ++ __asm__ __volatile__(LSS_BODY_ASM##nr LSS_ENTRYPOINT \ ++ : "=a" (__res) \ ++ : "0" (__NR_##name) LSS_BODY_ARG##nr(__VA_ARGS__) \ ++ : LSS_BODY_CLOBBER##nr "r11", "rcx", "memory"); \ ++ _LSS_RETURN(type, __res, cast) ++ #undef LSS_BODY ++ #define LSS_BODY(nr, type, name, args...) \ ++ _LSS_BODY(nr, type, name, uintptr_t, ## args) ++ ++ #undef LSS_BODY_ASM0 ++ #undef LSS_BODY_ASM1 ++ #undef LSS_BODY_ASM2 ++ #undef LSS_BODY_ASM3 ++ #undef LSS_BODY_ASM4 ++ #undef LSS_BODY_ASM5 ++ #undef LSS_BODY_ASM6 ++ #define LSS_BODY_ASM0 ++ #define LSS_BODY_ASM1 LSS_BODY_ASM0 ++ #define LSS_BODY_ASM2 LSS_BODY_ASM1 ++ #define LSS_BODY_ASM3 LSS_BODY_ASM2 ++ #define LSS_BODY_ASM4 LSS_BODY_ASM3 "movq %5,%%r10;" ++ #define LSS_BODY_ASM5 LSS_BODY_ASM4 "movq %6,%%r8;" ++ #define LSS_BODY_ASM6 LSS_BODY_ASM5 "movq %7,%%r9;" ++ ++ #undef LSS_BODY_CLOBBER0 ++ #undef LSS_BODY_CLOBBER1 ++ #undef LSS_BODY_CLOBBER2 ++ #undef LSS_BODY_CLOBBER3 ++ #undef LSS_BODY_CLOBBER4 ++ #undef LSS_BODY_CLOBBER5 ++ #undef LSS_BODY_CLOBBER6 ++ #define LSS_BODY_CLOBBER0 ++ #define LSS_BODY_CLOBBER1 LSS_BODY_CLOBBER0 ++ #define LSS_BODY_CLOBBER2 LSS_BODY_CLOBBER1 ++ #define LSS_BODY_CLOBBER3 LSS_BODY_CLOBBER2 ++ #define LSS_BODY_CLOBBER4 LSS_BODY_CLOBBER3 "r10", ++ #define LSS_BODY_CLOBBER5 LSS_BODY_CLOBBER4 "r8", ++ #define LSS_BODY_CLOBBER6 LSS_BODY_CLOBBER5 "r9", ++ ++ #undef LSS_BODY_ARG0 ++ #undef LSS_BODY_ARG1 ++ #undef LSS_BODY_ARG2 ++ #undef LSS_BODY_ARG3 ++ #undef LSS_BODY_ARG4 ++ #undef LSS_BODY_ARG5 ++ #undef LSS_BODY_ARG6 ++ #define LSS_BODY_ARG0() ++ #define LSS_BODY_ARG1(arg1) \ ++ LSS_BODY_ARG0(), "D" (arg1) ++ #define LSS_BODY_ARG2(arg1, arg2) \ ++ LSS_BODY_ARG1(arg1), "S" (arg2) ++ #define LSS_BODY_ARG3(arg1, arg2, arg3) \ ++ LSS_BODY_ARG2(arg1, arg2), "d" (arg3) ++ #define LSS_BODY_ARG4(arg1, arg2, arg3, arg4) \ ++ LSS_BODY_ARG3(arg1, arg2, arg3), "r" (arg4) ++ #define LSS_BODY_ARG5(arg1, arg2, arg3, arg4, arg5) \ ++ LSS_BODY_ARG4(arg1, arg2, arg3, arg4), "r" (arg5) ++ #define LSS_BODY_ARG6(arg1, arg2, arg3, arg4, arg5, arg6) \ ++ LSS_BODY_ARG5(arg1, arg2, arg3, arg4, arg5), "r" (arg6) ++ ++ #undef _syscall0 ++ #define _syscall0(type,name) \ ++ type LSS_NAME(name)(void) { \ ++ LSS_BODY(0, type, name); \ ++ } ++ #undef _syscall1 ++ #define _syscall1(type,name,type1,arg1) \ ++ type LSS_NAME(name)(type1 arg1) { \ ++ LSS_BODY(1, type, name, LSS_SYSCALL_ARG(arg1)); \ ++ } ++ #undef _syscall2 ++ #define _syscall2(type,name,type1,arg1,type2,arg2) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2) { \ ++ LSS_BODY(2, type, name, LSS_SYSCALL_ARG(arg1), LSS_SYSCALL_ARG(arg2));\ ++ } ++ #undef _syscall3 ++ #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ ++ LSS_BODY(3, type, name, LSS_SYSCALL_ARG(arg1), LSS_SYSCALL_ARG(arg2), \ ++ LSS_SYSCALL_ARG(arg3)); \ ++ } ++ #undef _syscall4 ++ #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ ++ LSS_BODY(4, type, name, LSS_SYSCALL_ARG(arg1), LSS_SYSCALL_ARG(arg2), \ ++ LSS_SYSCALL_ARG(arg3), LSS_SYSCALL_ARG(arg4));\ ++ } ++ #undef _syscall5 ++ #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5) { \ ++ LSS_BODY(5, type, name, LSS_SYSCALL_ARG(arg1), LSS_SYSCALL_ARG(arg2), \ ++ LSS_SYSCALL_ARG(arg3), LSS_SYSCALL_ARG(arg4), \ ++ LSS_SYSCALL_ARG(arg5)); \ ++ } ++ #undef _syscall6 ++ #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5,type6,arg6) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5, type6 arg6) { \ ++ LSS_BODY(6, type, name, LSS_SYSCALL_ARG(arg1), LSS_SYSCALL_ARG(arg2), \ ++ LSS_SYSCALL_ARG(arg3), LSS_SYSCALL_ARG(arg4), \ ++ LSS_SYSCALL_ARG(arg5), LSS_SYSCALL_ARG(arg6));\ ++ } ++ LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, ++ int flags, void *arg, int *parent_tidptr, ++ void *newtls, int *child_tidptr) { ++ long long __res; ++ { ++ __asm__ __volatile__(/* if (fn == NULL) ++ * return -EINVAL; ++ */ ++ "testq %4,%4\n" ++ "jz 1f\n" ++ ++ /* if (child_stack == NULL) ++ * return -EINVAL; ++ */ ++ "testq %5,%5\n" ++ "jz 1f\n" ++ ++ /* childstack -= 2*sizeof(void *); ++ */ ++ "subq $16,%5\n" ++ ++ /* Push "arg" and "fn" onto the stack that will be ++ * used by the child. ++ */ ++ "movq %7,8(%5)\n" ++ "movq %4,0(%5)\n" ++ ++ /* %rax = syscall(%rax = __NR_clone, ++ * %rdi = flags, ++ * %rsi = child_stack, ++ * %rdx = parent_tidptr, ++ * %r8 = new_tls, ++ * %r10 = child_tidptr) ++ */ ++ "movq %2,%%rax\n" ++ "movq %9,%%r8\n" ++ "movq %10,%%r10\n" ++ LSS_ENTRYPOINT ++ ++ /* if (%rax != 0) ++ * return; ++ */ ++ "testq %%rax,%%rax\n" ++ "jnz 1f\n" ++ ++ /* In the child. Terminate frame pointer chain. ++ */ ++ "xorq %%rbp,%%rbp\n" ++ ++ /* Call "fn(arg)". ++ */ ++ "popq %%rax\n" ++ "popq %%rdi\n" ++ "call *%%rax\n" ++ ++ /* Call _exit(%ebx). ++ */ ++ "movq %%rax,%%rdi\n" ++ "movq %3,%%rax\n" ++ LSS_ENTRYPOINT ++ ++ /* Return to parent. ++ */ ++ "1:\n" ++ : "=a" (__res) ++ : "0"(-EINVAL), "i"(__NR_clone), "i"(__NR_exit), ++ "r"(LSS_SYSCALL_ARG(fn)), ++ "S"(LSS_SYSCALL_ARG(child_stack)), ++ "D"(LSS_SYSCALL_ARG(flags)), ++ "r"(LSS_SYSCALL_ARG(arg)), ++ "d"(LSS_SYSCALL_ARG(parent_tidptr)), ++ "r"(LSS_SYSCALL_ARG(newtls)), ++ "r"(LSS_SYSCALL_ARG(child_tidptr)) ++ : "memory", "r8", "r10", "r11", "rcx"); ++ } ++ LSS_RETURN(int, __res); ++ } ++ LSS_INLINE _syscall2(int, arch_prctl, int, c, void *, a) ++ ++ LSS_INLINE void (*LSS_NAME(restore_rt)(void))(void) { ++ /* On x86-64, the kernel does not know how to return from ++ * a signal handler. Instead, it relies on user space to provide a ++ * restorer function that calls the rt_sigreturn() system call. ++ * Unfortunately, we cannot just reference the glibc version of this ++ * function, as glibc goes out of its way to make it inaccessible. ++ */ ++ long long res; ++ __asm__ __volatile__("jmp 2f\n" ++ ".align 16\n" ++ "1:movq %1,%%rax\n" ++ LSS_ENTRYPOINT ++ "2:leaq 1b(%%rip),%0\n" ++ : "=r" (res) ++ : "i" (__NR_rt_sigreturn)); ++ return (void (*)(void))(uintptr_t)res; ++ } ++ #elif defined(__ARM_ARCH_3__) ++ /* Most definitions of _syscallX() neglect to mark "memory" as being ++ * clobbered. This causes problems with compilers, that do a better job ++ * at optimizing across __asm__ calls. ++ * So, we just have to redefine all of the _syscallX() macros. ++ */ ++ #undef LSS_REG ++ #define LSS_REG(r,a) register long __r##r __asm__("r"#r) = (long)a ++ #undef LSS_BODY ++ #define LSS_BODY(type,name,args...) \ ++ register long __res_r0 __asm__("r0"); \ ++ long __res; \ ++ __asm__ __volatile__ (__syscall(name) \ ++ : "=r"(__res_r0) : args : "lr", "memory"); \ ++ __res = __res_r0; \ ++ LSS_RETURN(type, __res) ++ #undef _syscall0 ++ #define _syscall0(type, name) \ ++ type LSS_NAME(name)(void) { \ ++ LSS_BODY(type, name); \ ++ } ++ #undef _syscall1 ++ #define _syscall1(type, name, type1, arg1) \ ++ type LSS_NAME(name)(type1 arg1) { \ ++ LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ ++ } ++ #undef _syscall2 ++ #define _syscall2(type, name, type1, arg1, type2, arg2) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ ++ } ++ #undef _syscall3 ++ #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ ++ } ++ #undef _syscall4 ++ #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_REG(3, arg4); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ ++ } ++ #undef _syscall5 ++ #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_REG(3, arg4); LSS_REG(4, arg5); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ ++ "r"(__r4)); \ ++ } ++ #undef _syscall6 ++ #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5,type6,arg6) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5, type6 arg6) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ ++ "r"(__r4), "r"(__r5)); \ ++ } ++ LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, ++ int flags, void *arg, int *parent_tidptr, ++ void *newtls, int *child_tidptr) { ++ long __res; ++ { ++ register int __flags __asm__("r0") = flags; ++ register void *__stack __asm__("r1") = child_stack; ++ register void *__ptid __asm__("r2") = parent_tidptr; ++ register void *__tls __asm__("r3") = newtls; ++ register int *__ctid __asm__("r4") = child_tidptr; ++ __asm__ __volatile__(/* if (fn == NULL || child_stack == NULL) ++ * return -EINVAL; ++ */ ++ "cmp %2,#0\n" ++ "cmpne %3,#0\n" ++ "moveq %0,%1\n" ++ "beq 1f\n" ++ ++ /* Push "arg" and "fn" onto the stack that will be ++ * used by the child. ++ */ ++ "str %5,[%3,#-4]!\n" ++ "str %2,[%3,#-4]!\n" ++ ++ /* %r0 = syscall(%r0 = flags, ++ * %r1 = child_stack, ++ * %r2 = parent_tidptr, ++ * %r3 = newtls, ++ * %r4 = child_tidptr) ++ */ ++ __syscall(clone)"\n" ++ ++ /* if (%r0 != 0) ++ * return %r0; ++ */ ++ "movs %0,r0\n" ++ "bne 1f\n" ++ ++ /* In the child, now. Call "fn(arg)". ++ */ ++ "ldr r0,[sp, #4]\n" ++ "mov lr,pc\n" ++ "ldr pc,[sp]\n" ++ ++ /* Call _exit(%r0). ++ */ ++ __syscall(exit)"\n" ++ "1:\n" ++ : "=r" (__res) ++ : "i"(-EINVAL), ++ "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), ++ "r"(__ptid), "r"(__tls), "r"(__ctid) ++ : "cc", "lr", "memory"); ++ } ++ LSS_RETURN(int, __res); ++ } ++ #elif defined(__ARM_EABI__) ++ /* Most definitions of _syscallX() neglect to mark "memory" as being ++ * clobbered. This causes problems with compilers, that do a better job ++ * at optimizing across __asm__ calls. ++ * So, we just have to redefine all fo the _syscallX() macros. ++ */ ++ #undef LSS_REG ++ #define LSS_REG(r,a) register long __r##r __asm__("r"#r) = (long)a ++ #undef LSS_BODY ++ #define LSS_BODY(type,name,args...) \ ++ register long __res_r0 __asm__("r0"); \ ++ long __res; \ ++ __asm__ __volatile__ ("push {r7}\n" \ ++ "mov r7, %1\n" \ ++ "swi 0x0\n" \ ++ "pop {r7}\n" \ ++ : "=r"(__res_r0) \ ++ : "i"(__NR_##name) , ## args \ ++ : "lr", "memory"); \ ++ __res = __res_r0; \ ++ LSS_RETURN(type, __res) ++ #undef _syscall0 ++ #define _syscall0(type, name) \ ++ type LSS_NAME(name)(void) { \ ++ LSS_BODY(type, name); \ ++ } ++ #undef _syscall1 ++ #define _syscall1(type, name, type1, arg1) \ ++ type LSS_NAME(name)(type1 arg1) { \ ++ LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ ++ } ++ #undef _syscall2 ++ #define _syscall2(type, name, type1, arg1, type2, arg2) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ ++ } ++ #undef _syscall3 ++ #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ ++ } ++ #undef _syscall4 ++ #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_REG(3, arg4); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ ++ } ++ #undef _syscall5 ++ #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_REG(3, arg4); LSS_REG(4, arg5); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ ++ "r"(__r4)); \ ++ } ++ #undef _syscall6 ++ #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5,type6,arg6) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5, type6 arg6) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ ++ "r"(__r4), "r"(__r5)); \ ++ } ++ LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, ++ int flags, void *arg, int *parent_tidptr, ++ void *newtls, int *child_tidptr) { ++ long __res; ++ if (fn == NULL || child_stack == NULL) { ++ __res = -EINVAL; ++ LSS_RETURN(int, __res); ++ } ++ ++ /* Push "arg" and "fn" onto the stack that will be ++ * used by the child. ++ */ ++ { ++ uintptr_t* cstack = (uintptr_t*)child_stack - 2; ++ cstack[0] = (uintptr_t)fn; ++ cstack[1] = (uintptr_t)arg; ++ child_stack = cstack; ++ } ++ { ++ register int __flags __asm__("r0") = flags; ++ register void *__stack __asm__("r1") = child_stack; ++ register void *__ptid __asm__("r2") = parent_tidptr; ++ register void *__tls __asm__("r3") = newtls; ++ register int *__ctid __asm__("r4") = child_tidptr; ++ __asm__ __volatile__( ++#ifdef __thumb2__ ++ "push {r7}\n" ++#endif ++ /* %r0 = syscall(%r0 = flags, ++ * %r1 = child_stack, ++ * %r2 = parent_tidptr, ++ * %r3 = newtls, ++ * %r4 = child_tidptr) ++ */ ++ "mov r7, %6\n" ++ "swi 0x0\n" ++ ++ /* if (%r0 != 0) ++ * return %r0; ++ */ ++ "cmp r0, #0\n" ++ "bne 1f\n" ++ ++ /* In the child, now. Call "fn(arg)". ++ */ ++ "ldr r0,[sp, #4]\n" ++ ++ "ldr lr,[sp]\n" ++ "blx lr\n" ++ ++ /* Call _exit(%r0). ++ */ ++ "mov r7, %7\n" ++ "swi 0x0\n" ++ /* Unreachable */ ++ "bkpt #0\n" ++ "1:\n" ++#ifdef __thumb2__ ++ "pop {r7}\n" ++#endif ++ "movs %0,r0\n" ++ : "=r"(__res) ++ : "r"(__stack), "r"(__flags), "r"(__ptid), "r"(__tls), "r"(__ctid), ++ "i"(__NR_clone), "i"(__NR_exit) ++ : "cc", "lr", "memory" ++#ifndef __thumb2__ ++ , "r7" ++#endif ++ ); ++ } ++ LSS_RETURN(int, __res); ++ } ++ #elif defined(__aarch64__) ++ /* Most definitions of _syscallX() neglect to mark "memory" as being ++ * clobbered. This causes problems with compilers, that do a better job ++ * at optimizing across __asm__ calls. ++ * So, we just have to redefine all of the _syscallX() macros. ++ */ ++ #undef LSS_REG ++ #define LSS_REG(r,a) register int64_t __r##r __asm__("x"#r) = (int64_t)a ++ #undef LSS_BODY ++ #define LSS_BODY(type,name,args...) \ ++ register int64_t __res_x0 __asm__("x0"); \ ++ int64_t __res; \ ++ __asm__ __volatile__ ("mov x8, %1\n" \ ++ "svc 0x0\n" \ ++ : "=r"(__res_x0) \ ++ : "i"(__NR_##name) , ## args \ ++ : "x8", "memory"); \ ++ __res = __res_x0; \ ++ LSS_RETURN(type, __res) ++ #undef _syscall0 ++ #define _syscall0(type, name) \ ++ type LSS_NAME(name)(void) { \ ++ LSS_BODY(type, name); \ ++ } ++ #undef _syscall1 ++ #define _syscall1(type, name, type1, arg1) \ ++ type LSS_NAME(name)(type1 arg1) { \ ++ LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ ++ } ++ #undef _syscall2 ++ #define _syscall2(type, name, type1, arg1, type2, arg2) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ ++ } ++ #undef _syscall3 ++ #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ ++ } ++ #undef _syscall4 ++ #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_REG(3, arg4); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ ++ } ++ #undef _syscall5 ++ #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_REG(3, arg4); LSS_REG(4, arg5); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ ++ "r"(__r4)); \ ++ } ++ #undef _syscall6 ++ #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5,type6,arg6) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5, type6 arg6) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ ++ "r"(__r4), "r"(__r5)); \ ++ } ++ ++ LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, ++ int flags, void *arg, int *parent_tidptr, ++ void *newtls, int *child_tidptr) { ++ int64_t __res; ++ { ++ register uint64_t __flags __asm__("x0") = (uint64_t)flags; ++ register void *__stack __asm__("x1") = child_stack; ++ register void *__ptid __asm__("x2") = parent_tidptr; ++ register void *__tls __asm__("x3") = newtls; ++ register int *__ctid __asm__("x4") = child_tidptr; ++ __asm__ __volatile__(/* Push "arg" and "fn" onto the stack that will be ++ * used by the child. ++ */ ++ "stp %1, %4, [%2, #-16]!\n" ++ ++ /* %x0 = syscall(%x0 = flags, ++ * %x1 = child_stack, ++ * %x2 = parent_tidptr, ++ * %x3 = newtls, ++ * %x4 = child_tidptr) ++ */ ++ "mov x8, %8\n" ++ "svc 0x0\n" ++ ++ /* if (%r0 != 0) ++ * return %r0; ++ */ ++ "mov %0, x0\n" ++ "cbnz x0, 1f\n" ++ ++ /* In the child, now. Call "fn(arg)". ++ */ ++ "ldp x1, x0, [sp], #16\n" ++ "blr x1\n" ++ ++ /* Call _exit(%r0). ++ */ ++ "mov x8, %9\n" ++ "svc 0x0\n" ++ "1:\n" ++ : "=r" (__res) ++ : "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), ++ "r"(__ptid), "r"(__tls), "r"(__ctid), ++ "i"(__NR_clone), "i"(__NR_exit) ++ : "cc", "x8", "memory"); ++ } ++ LSS_RETURN(int, __res); ++ } ++ #elif defined(__mips__) ++ #undef LSS_REG ++ #define LSS_REG(r,a) register unsigned long __r##r __asm__("$"#r) = \ ++ (unsigned long)(a) ++ #undef LSS_BODY ++ #undef LSS_SYSCALL_CLOBBERS ++ #if _MIPS_SIM == _MIPS_SIM_ABI32 ++ #define LSS_SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", \ ++ "$11", "$12", "$13", "$14", "$15", \ ++ "$24", "$25", "hi", "lo", "memory" ++ #else ++ #define LSS_SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", \ ++ "$13", "$14", "$15", "$24", "$25", \ ++ "hi", "lo", "memory" ++ #endif ++ #define LSS_BODY(type,name,r7,...) \ ++ register unsigned long __v0 __asm__("$2") = __NR_##name; \ ++ __asm__ __volatile__ ("syscall\n" \ ++ : "=r"(__v0), r7 (__r7) \ ++ : "0"(__v0), ##__VA_ARGS__ \ ++ : LSS_SYSCALL_CLOBBERS); \ ++ LSS_RETURN(type, __v0, __r7) ++ #undef _syscall0 ++ #define _syscall0(type, name) \ ++ type LSS_NAME(name)(void) { \ ++ register unsigned long __r7 __asm__("$7"); \ ++ LSS_BODY(type, name, "=r"); \ ++ } ++ #undef _syscall1 ++ #define _syscall1(type, name, type1, arg1) \ ++ type LSS_NAME(name)(type1 arg1) { \ ++ register unsigned long __r7 __asm__("$7"); \ ++ LSS_REG(4, arg1); LSS_BODY(type, name, "=r", "r"(__r4)); \ ++ } ++ #undef _syscall2 ++ #define _syscall2(type, name, type1, arg1, type2, arg2) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2) { \ ++ register unsigned long __r7 __asm__("$7"); \ ++ LSS_REG(4, arg1); LSS_REG(5, arg2); \ ++ LSS_BODY(type, name, "=r", "r"(__r4), "r"(__r5)); \ ++ } ++ #undef _syscall3 ++ #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ ++ register unsigned long __r7 __asm__("$7"); \ ++ LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ ++ LSS_BODY(type, name, "=r", "r"(__r4), "r"(__r5), "r"(__r6)); \ ++ } ++ #undef _syscall4 ++ #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ ++ LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ ++ LSS_REG(7, arg4); \ ++ LSS_BODY(type, name, "+r", "r"(__r4), "r"(__r5), "r"(__r6)); \ ++ } ++ #undef _syscall5 ++ #if _MIPS_SIM == _MIPS_SIM_ABI32 ++ /* The old 32bit MIPS system call API passes the fifth and sixth argument ++ * on the stack, whereas the new APIs use registers "r8" and "r9". ++ */ ++ #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5) { \ ++ LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ ++ LSS_REG(7, arg4); \ ++ register unsigned long __v0 __asm__("$2") = __NR_##name; \ ++ __asm__ __volatile__ (".set noreorder\n" \ ++ "subu $29, 32\n" \ ++ "sw %5, 16($29)\n" \ ++ "syscall\n" \ ++ "addiu $29, 32\n" \ ++ ".set reorder\n" \ ++ : "+r"(__v0), "+r" (__r7) \ ++ : "r"(__r4), "r"(__r5), \ ++ "r"(__r6), "r" ((unsigned long)arg5) \ ++ : "$8", "$9", "$10", "$11", "$12", \ ++ "$13", "$14", "$15", "$24", "$25", \ ++ "memory"); \ ++ LSS_RETURN(type, __v0, __r7); \ ++ } ++ #else ++ #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5) { \ ++ LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ ++ LSS_REG(7, arg4); LSS_REG(8, arg5); \ ++ LSS_BODY(type, name, "+r", "r"(__r4), "r"(__r5), "r"(__r6), \ ++ "r"(__r8)); \ ++ } ++ #endif ++ #undef _syscall6 ++ #if _MIPS_SIM == _MIPS_SIM_ABI32 ++ /* The old 32bit MIPS system call API passes the fifth and sixth argument ++ * on the stack, whereas the new APIs use registers "r8" and "r9". ++ */ ++ #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5,type6,arg6) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5, type6 arg6) { \ ++ LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ ++ LSS_REG(7, arg4); \ ++ register unsigned long __v0 __asm__("$2") = __NR_##name; \ ++ __asm__ __volatile__ (".set noreorder\n" \ ++ "subu $29, 32\n" \ ++ "sw %5, 16($29)\n" \ ++ "sw %6, 20($29)\n" \ ++ "syscall\n" \ ++ "addiu $29, 32\n" \ ++ ".set reorder\n" \ ++ : "+r"(__v0), "+r" (__r7) \ ++ : "r"(__r4), "r"(__r5), \ ++ "r"(__r6), "r" ((unsigned long)arg5), \ ++ "r" ((unsigned long)arg6) \ ++ : "$8", "$9", "$10", "$11", "$12", \ ++ "$13", "$14", "$15", "$24", "$25", \ ++ "memory"); \ ++ LSS_RETURN(type, __v0, __r7); \ ++ } ++ #else ++ #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5,type6,arg6) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5,type6 arg6) { \ ++ LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ ++ LSS_REG(7, arg4); LSS_REG(8, arg5); LSS_REG(9, arg6); \ ++ LSS_BODY(type, name, "+r", "r"(__r4), "r"(__r5), "r"(__r6), \ ++ "r"(__r8), "r"(__r9)); \ ++ } ++ #endif ++ LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, ++ int flags, void *arg, int *parent_tidptr, ++ void *newtls, int *child_tidptr) { ++ register unsigned long __v0 __asm__("$2") = -EINVAL; ++ register unsigned long __r7 __asm__("$7") = (unsigned long)newtls; ++ { ++ register int __flags __asm__("$4") = flags; ++ register void *__stack __asm__("$5") = child_stack; ++ register void *__ptid __asm__("$6") = parent_tidptr; ++ register int *__ctid __asm__("$8") = child_tidptr; ++ __asm__ __volatile__( ++ #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32 ++ "subu $29,24\n" ++ #elif _MIPS_SIM == _MIPS_SIM_NABI32 ++ "sub $29,16\n" ++ #else ++ "dsubu $29,16\n" ++ #endif ++ ++ /* if (fn == NULL || child_stack == NULL) ++ * return -EINVAL; ++ */ ++ "beqz %4,1f\n" ++ "beqz %5,1f\n" ++ ++ /* Push "arg" and "fn" onto the stack that will be ++ * used by the child. ++ */ ++ #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32 ++ "subu %5,32\n" ++ "sw %4,0(%5)\n" ++ "sw %7,4(%5)\n" ++ #elif _MIPS_SIM == _MIPS_SIM_NABI32 ++ "sub %5,32\n" ++ "sw %4,0(%5)\n" ++ "sw %7,8(%5)\n" ++ #else ++ "dsubu %5,32\n" ++ "sd %4,0(%5)\n" ++ "sd %7,8(%5)\n" ++ #endif ++ ++ /* $7 = syscall($4 = flags, ++ * $5 = child_stack, ++ * $6 = parent_tidptr, ++ * $7 = newtls, ++ * $8 = child_tidptr) ++ */ ++ "li $2,%2\n" ++ "syscall\n" ++ ++ /* if ($7 != 0) ++ * return $2; ++ */ ++ "bnez $7,1f\n" ++ "bnez $2,1f\n" ++ ++ /* In the child, now. Call "fn(arg)". ++ */ ++ #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32 ++ "lw $25,0($29)\n" ++ "lw $4,4($29)\n" ++ #elif _MIPS_SIM == _MIPS_SIM_NABI32 ++ "lw $25,0($29)\n" ++ "lw $4,8($29)\n" ++ #else ++ "ld $25,0($29)\n" ++ "ld $4,8($29)\n" ++ #endif ++ "jalr $25\n" ++ ++ /* Call _exit($2) ++ */ ++ "move $4,$2\n" ++ "li $2,%3\n" ++ "syscall\n" ++ ++ "1:\n" ++ #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32 ++ "addu $29, 24\n" ++ #elif _MIPS_SIM == _MIPS_SIM_NABI32 ++ "add $29, 16\n" ++ #else ++ "daddu $29,16\n" ++ #endif ++ : "+r" (__v0), "+r" (__r7) ++ : "i"(__NR_clone), "i"(__NR_exit), "r"(fn), ++ "r"(__stack), "r"(__flags), "r"(arg), ++ "r"(__ptid), "r"(__ctid) ++ : "$9", "$10", "$11", "$12", "$13", "$14", "$15", ++ "$24", "$25", "memory"); ++ } ++ LSS_RETURN(int, __v0, __r7); ++ } ++ #elif defined (__PPC__) ++ #undef LSS_LOADARGS_0 ++ #define LSS_LOADARGS_0(name, dummy...) \ ++ __sc_0 = __NR_##name ++ #undef LSS_LOADARGS_1 ++ #define LSS_LOADARGS_1(name, arg1) \ ++ LSS_LOADARGS_0(name); \ ++ __sc_3 = (unsigned long) (arg1) ++ #undef LSS_LOADARGS_2 ++ #define LSS_LOADARGS_2(name, arg1, arg2) \ ++ LSS_LOADARGS_1(name, arg1); \ ++ __sc_4 = (unsigned long) (arg2) ++ #undef LSS_LOADARGS_3 ++ #define LSS_LOADARGS_3(name, arg1, arg2, arg3) \ ++ LSS_LOADARGS_2(name, arg1, arg2); \ ++ __sc_5 = (unsigned long) (arg3) ++ #undef LSS_LOADARGS_4 ++ #define LSS_LOADARGS_4(name, arg1, arg2, arg3, arg4) \ ++ LSS_LOADARGS_3(name, arg1, arg2, arg3); \ ++ __sc_6 = (unsigned long) (arg4) ++ #undef LSS_LOADARGS_5 ++ #define LSS_LOADARGS_5(name, arg1, arg2, arg3, arg4, arg5) \ ++ LSS_LOADARGS_4(name, arg1, arg2, arg3, arg4); \ ++ __sc_7 = (unsigned long) (arg5) ++ #undef LSS_LOADARGS_6 ++ #define LSS_LOADARGS_6(name, arg1, arg2, arg3, arg4, arg5, arg6) \ ++ LSS_LOADARGS_5(name, arg1, arg2, arg3, arg4, arg5); \ ++ __sc_8 = (unsigned long) (arg6) ++ #undef LSS_ASMINPUT_0 ++ #define LSS_ASMINPUT_0 "0" (__sc_0) ++ #undef LSS_ASMINPUT_1 ++ #define LSS_ASMINPUT_1 LSS_ASMINPUT_0, "1" (__sc_3) ++ #undef LSS_ASMINPUT_2 ++ #define LSS_ASMINPUT_2 LSS_ASMINPUT_1, "2" (__sc_4) ++ #undef LSS_ASMINPUT_3 ++ #define LSS_ASMINPUT_3 LSS_ASMINPUT_2, "3" (__sc_5) ++ #undef LSS_ASMINPUT_4 ++ #define LSS_ASMINPUT_4 LSS_ASMINPUT_3, "4" (__sc_6) ++ #undef LSS_ASMINPUT_5 ++ #define LSS_ASMINPUT_5 LSS_ASMINPUT_4, "5" (__sc_7) ++ #undef LSS_ASMINPUT_6 ++ #define LSS_ASMINPUT_6 LSS_ASMINPUT_5, "6" (__sc_8) ++ #undef LSS_BODY ++ #define LSS_BODY(nr, type, name, args...) \ ++ long __sc_ret, __sc_err; \ ++ { \ ++ register unsigned long __sc_0 __asm__ ("r0"); \ ++ register unsigned long __sc_3 __asm__ ("r3"); \ ++ register unsigned long __sc_4 __asm__ ("r4"); \ ++ register unsigned long __sc_5 __asm__ ("r5"); \ ++ register unsigned long __sc_6 __asm__ ("r6"); \ ++ register unsigned long __sc_7 __asm__ ("r7"); \ ++ register unsigned long __sc_8 __asm__ ("r8"); \ ++ \ ++ LSS_LOADARGS_##nr(name, args); \ ++ __asm__ __volatile__ \ ++ ("sc\n\t" \ ++ "mfcr %0" \ ++ : "=&r" (__sc_0), \ ++ "=&r" (__sc_3), "=&r" (__sc_4), \ ++ "=&r" (__sc_5), "=&r" (__sc_6), \ ++ "=&r" (__sc_7), "=&r" (__sc_8) \ ++ : LSS_ASMINPUT_##nr \ ++ : "cr0", "ctr", "memory", \ ++ "r9", "r10", "r11", "r12"); \ ++ __sc_ret = __sc_3; \ ++ __sc_err = __sc_0; \ ++ } \ ++ LSS_RETURN(type, __sc_ret, __sc_err) ++ #undef _syscall0 ++ #define _syscall0(type, name) \ ++ type LSS_NAME(name)(void) { \ ++ LSS_BODY(0, type, name); \ ++ } ++ #undef _syscall1 ++ #define _syscall1(type, name, type1, arg1) \ ++ type LSS_NAME(name)(type1 arg1) { \ ++ LSS_BODY(1, type, name, arg1); \ ++ } ++ #undef _syscall2 ++ #define _syscall2(type, name, type1, arg1, type2, arg2) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2) { \ ++ LSS_BODY(2, type, name, arg1, arg2); \ ++ } ++ #undef _syscall3 ++ #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ ++ LSS_BODY(3, type, name, arg1, arg2, arg3); \ ++ } ++ #undef _syscall4 ++ #define _syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \ ++ type4, arg4) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ ++ LSS_BODY(4, type, name, arg1, arg2, arg3, arg4); \ ++ } ++ #undef _syscall5 ++ #define _syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \ ++ type4, arg4, type5, arg5) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5) { \ ++ LSS_BODY(5, type, name, arg1, arg2, arg3, arg4, arg5); \ ++ } ++ #undef _syscall6 ++ #define _syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \ ++ type4, arg4, type5, arg5, type6, arg6) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5, type6 arg6) { \ ++ LSS_BODY(6, type, name, arg1, arg2, arg3, arg4, arg5, arg6); \ ++ } ++ /* clone function adapted from glibc 2.3.6 clone.S */ ++ /* TODO(csilvers): consider wrapping some args up in a struct, like we ++ * do for i386's _syscall6, so we can compile successfully on gcc 2.95 ++ */ ++ LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, ++ int flags, void *arg, int *parent_tidptr, ++ void *newtls, int *child_tidptr) { ++ long __ret, __err; ++ { ++ register int (*__fn)(void *) __asm__ ("r8") = fn; ++ register void *__cstack __asm__ ("r4") = child_stack; ++ register int __flags __asm__ ("r3") = flags; ++ register void * __arg __asm__ ("r9") = arg; ++ register int * __ptidptr __asm__ ("r5") = parent_tidptr; ++ register void * __newtls __asm__ ("r6") = newtls; ++ register int * __ctidptr __asm__ ("r7") = child_tidptr; ++ __asm__ __volatile__( ++ /* check for fn == NULL ++ * and child_stack == NULL ++ */ ++ "cmpwi cr0, %6, 0\n\t" ++ "cmpwi cr1, %7, 0\n\t" ++ "cror cr0*4+eq, cr1*4+eq, cr0*4+eq\n\t" ++ "beq- cr0, 1f\n\t" ++ ++ /* set up stack frame for child */ ++ "clrrwi %7, %7, 4\n\t" ++ "li 0, 0\n\t" ++ "stwu 0, -16(%7)\n\t" ++ ++ /* fn, arg, child_stack are saved across the syscall: r28-30 */ ++ "mr 28, %6\n\t" ++ "mr 29, %7\n\t" ++ "mr 27, %9\n\t" ++ ++ /* syscall */ ++ "li 0, %4\n\t" ++ /* flags already in r3 ++ * child_stack already in r4 ++ * ptidptr already in r5 ++ * newtls already in r6 ++ * ctidptr already in r7 ++ */ ++ "sc\n\t" ++ ++ /* Test if syscall was successful */ ++ "cmpwi cr1, 3, 0\n\t" ++ "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t" ++ "bne- cr1, 1f\n\t" ++ ++ /* Do the function call */ ++ "mtctr 28\n\t" ++ "mr 3, 27\n\t" ++ "bctrl\n\t" ++ ++ /* Call _exit(r3) */ ++ "li 0, %5\n\t" ++ "sc\n\t" ++ ++ /* Return to parent */ ++ "1:\n" ++ "mfcr %1\n\t" ++ "mr %0, 3\n\t" ++ : "=r" (__ret), "=r" (__err) ++ : "0" (-1), "1" (EINVAL), ++ "i" (__NR_clone), "i" (__NR_exit), ++ "r" (__fn), "r" (__cstack), "r" (__flags), ++ "r" (__arg), "r" (__ptidptr), "r" (__newtls), ++ "r" (__ctidptr) ++ : "cr0", "cr1", "memory", "ctr", ++ "r0", "r29", "r27", "r28"); ++ } ++ LSS_RETURN(int, __ret, __err); ++ } ++ #elif defined(__s390__) ++ #undef LSS_REG ++ #define LSS_REG(r, a) register unsigned long __r##r __asm__("r"#r) = (unsigned long) a ++ #undef LSS_BODY ++ #define LSS_BODY(type, name, args...) \ ++ register unsigned long __nr __asm__("r1") \ ++ = (unsigned long)(__NR_##name); \ ++ register long __res_r2 __asm__("r2"); \ ++ long __res; \ ++ __asm__ __volatile__ \ ++ ("svc 0\n\t" \ ++ : "=d"(__res_r2) \ ++ : "d"(__nr), ## args \ ++ : "memory"); \ ++ __res = __res_r2; \ ++ LSS_RETURN(type, __res) ++ #undef _syscall0 ++ #define _syscall0(type, name) \ ++ type LSS_NAME(name)(void) { \ ++ LSS_BODY(type, name); \ ++ } ++ #undef _syscall1 ++ #define _syscall1(type, name, type1, arg1) \ ++ type LSS_NAME(name)(type1 arg1) { \ ++ LSS_REG(2, arg1); \ ++ LSS_BODY(type, name, "0"(__r2)); \ ++ } ++ #undef _syscall2 ++ #define _syscall2(type, name, type1, arg1, type2, arg2) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2) { \ ++ LSS_REG(2, arg1); LSS_REG(3, arg2); \ ++ LSS_BODY(type, name, "0"(__r2), "d"(__r3)); \ ++ } ++ #undef _syscall3 ++ #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ ++ LSS_REG(2, arg1); LSS_REG(3, arg2); LSS_REG(4, arg3); \ ++ LSS_BODY(type, name, "0"(__r2), "d"(__r3), "d"(__r4)); \ ++ } ++ #undef _syscall4 ++ #define _syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \ ++ type4, arg4) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, \ ++ type4 arg4) { \ ++ LSS_REG(2, arg1); LSS_REG(3, arg2); LSS_REG(4, arg3); \ ++ LSS_REG(5, arg4); \ ++ LSS_BODY(type, name, "0"(__r2), "d"(__r3), "d"(__r4), \ ++ "d"(__r5)); \ ++ } ++ #undef _syscall5 ++ #define _syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \ ++ type4, arg4, type5, arg5) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, \ ++ type4 arg4, type5 arg5) { \ ++ LSS_REG(2, arg1); LSS_REG(3, arg2); LSS_REG(4, arg3); \ ++ LSS_REG(5, arg4); LSS_REG(6, arg5); \ ++ LSS_BODY(type, name, "0"(__r2), "d"(__r3), "d"(__r4), \ ++ "d"(__r5), "d"(__r6)); \ ++ } ++ #undef _syscall6 ++ #define _syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \ ++ type4, arg4, type5, arg5, type6, arg6) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, \ ++ type4 arg4, type5 arg5, type6 arg6) { \ ++ LSS_REG(2, arg1); LSS_REG(3, arg2); LSS_REG(4, arg3); \ ++ LSS_REG(5, arg4); LSS_REG(6, arg5); LSS_REG(7, arg6); \ ++ LSS_BODY(type, name, "0"(__r2), "d"(__r3), "d"(__r4), \ ++ "d"(__r5), "d"(__r6), "d"(__r7)); \ ++ } ++ LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, ++ int flags, void *arg, int *parent_tidptr, ++ void *newtls, int *child_tidptr) { ++ long __ret; ++ { ++ register int (*__fn)(void *) __asm__ ("r1") = fn; ++ register void *__cstack __asm__ ("r2") = child_stack; ++ register int __flags __asm__ ("r3") = flags; ++ register void *__arg __asm__ ("r0") = arg; ++ register int *__ptidptr __asm__ ("r4") = parent_tidptr; ++ register void *__newtls __asm__ ("r6") = newtls; ++ register int *__ctidptr __asm__ ("r5") = child_tidptr; ++ __asm__ __volatile__ ( ++ #ifndef __s390x__ ++ /* arg already in r0 */ ++ "ltr %4, %4\n\t" /* check fn, which is already in r1 */ ++ "jz 1f\n\t" /* NULL function pointer, return -EINVAL */ ++ "ltr %5, %5\n\t" /* check child_stack, which is already in r2 */ ++ "jz 1f\n\t" /* NULL stack pointer, return -EINVAL */ ++ /* flags already in r3 */ ++ /* parent_tidptr already in r4 */ ++ /* child_tidptr already in r5 */ ++ /* newtls already in r6 */ ++ "svc %2\n\t" /* invoke clone syscall */ ++ "ltr %0,%%r2\n\t" /* load return code into __ret and test */ ++ "jnz 1f\n\t" /* return to parent if non-zero */ ++ /* start child thread */ ++ "lr %%r2, %7\n\t" /* set first parameter to void *arg */ ++ "ahi %%r15, -96\n\t" /* make room on the stack for the save area */ ++ "xc 0(4,%%r15), 0(%%r15)\n\t" ++ "basr %%r14, %4\n\t" /* jump to fn */ ++ "svc %3\n" /* invoke exit syscall */ ++ "1:\n" ++ #else ++ /* arg already in r0 */ ++ "ltgr %4, %4\n\t" /* check fn, which is already in r1 */ ++ "jz 1f\n\t" /* NULL function pointer, return -EINVAL */ ++ "ltgr %5, %5\n\t" /* check child_stack, which is already in r2 */ ++ "jz 1f\n\t" /* NULL stack pointer, return -EINVAL */ ++ /* flags already in r3 */ ++ /* parent_tidptr already in r4 */ ++ /* child_tidptr already in r5 */ ++ /* newtls already in r6 */ ++ "svc %2\n\t" /* invoke clone syscall */ ++ "ltgr %0, %%r2\n\t" /* load return code into __ret and test */ ++ "jnz 1f\n\t" /* return to parent if non-zero */ ++ /* start child thread */ ++ "lgr %%r2, %7\n\t" /* set first parameter to void *arg */ ++ "aghi %%r15, -160\n\t" /* make room on the stack for the save area */ ++ "xc 0(8,%%r15), 0(%%r15)\n\t" ++ "basr %%r14, %4\n\t" /* jump to fn */ ++ "svc %3\n" /* invoke exit syscall */ ++ "1:\n" ++ #endif ++ : "=r" (__ret) ++ : "0" (-EINVAL), "i" (__NR_clone), "i" (__NR_exit), ++ "d" (__fn), "d" (__cstack), "d" (__flags), "d" (__arg), ++ "d" (__ptidptr), "d" (__newtls), "d" (__ctidptr) ++ : "cc", "r14", "memory" ++ ); ++ } ++ LSS_RETURN(int, __ret); ++ } ++ #elif defined(__riscv) && __riscv_xlen == 64 ++ #undef LSS_REG ++ #define LSS_REG(r,a) register int64_t __r##r __asm__("a"#r) = (int64_t)a ++ #undef LSS_BODY ++ #define LSS_BODY(type,name,args...) \ ++ register int64_t __res_a0 __asm__("a0"); \ ++ register int64_t __a7 __asm__("a7") = __NR_##name; \ ++ int64_t __res; \ ++ __asm__ __volatile__ ("scall\n" \ ++ : "=r"(__res_a0) \ ++ : "r"(__a7) , ## args \ ++ : "memory"); \ ++ __res = __res_a0; \ ++ LSS_RETURN(type, __res) ++ #undef _syscall0 ++ #define _syscall0(type, name) \ ++ type LSS_NAME(name)(void) { \ ++ LSS_BODY(type, name); \ ++ } ++ #undef _syscall1 ++ #define _syscall1(type, name, type1, arg1) \ ++ type LSS_NAME(name)(type1 arg1) { \ ++ LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ ++ } ++ #undef _syscall2 ++ #define _syscall2(type, name, type1, arg1, type2, arg2) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ ++ } ++ #undef _syscall3 ++ #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ ++ } ++ #undef _syscall4 ++ #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_REG(3, arg4); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ ++ } ++ #undef _syscall5 ++ #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_REG(3, arg4); LSS_REG(4, arg5); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ ++ "r"(__r4)); \ ++ } ++ #undef _syscall6 ++ #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5,type6,arg6) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5, type6 arg6) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ ++ "r"(__r4), "r"(__r5)); \ ++ } ++ ++ LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, ++ int flags, void *arg, int *parent_tidptr, ++ void *newtls, int *child_tidptr) { ++ int64_t __res; ++ { ++ register int64_t __res_a0 __asm__("a0"); ++ register uint64_t __flags __asm__("a0") = flags; ++ register void *__stack __asm__("a1") = child_stack; ++ register void *__ptid __asm__("a2") = parent_tidptr; ++ register void *__tls __asm__("a3") = newtls; ++ register int *__ctid __asm__("a4") = child_tidptr; ++ __asm__ __volatile__(/* Push "arg" and "fn" onto the stack that will be ++ * used by the child. ++ */ ++ "addi %2,%2,-16\n" ++ "sd %1, 0(%2)\n" ++ "sd %4, 8(%2)\n" ++ ++ /* %a0 = syscall(%a0 = flags, ++ * %a1 = child_stack, ++ * %a2 = parent_tidptr, ++ * %a3 = newtls, ++ * %a4 = child_tidptr) ++ */ ++ "li a7, %8\n" ++ "scall\n" ++ ++ /* if (%a0 != 0) ++ * return %a0; ++ */ ++ "bnez %0, 1f\n" ++ ++ /* In the child, now. Call "fn(arg)". ++ */ ++ "ld a1, 0(sp)\n" ++ "ld a0, 8(sp)\n" ++ "jalr a1\n" ++ ++ /* Call _exit(%a0). ++ */ ++ "li a7, %9\n" ++ "scall\n" ++ "1:\n" ++ : "=r" (__res_a0) ++ : "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), ++ "r"(__ptid), "r"(__tls), "r"(__ctid), ++ "i"(__NR_clone), "i"(__NR_exit) ++ : "cc", "memory"); ++ __res = __res_a0; ++ } ++ LSS_RETURN(int, __res); ++ } ++ #elif defined(__e2k__) ++ ++ #undef _LSS_BODY ++ #define _LSS_BODY(nr, type, name, ...) \ ++ register unsigned long long __res; \ ++ __asm__ __volatile__ \ ++ ( \ ++ "{\n\t" \ ++ " sdisp %%ctpr1, 0x3\n\t" \ ++ " addd, s 0x0, %[sys_num], %%b[0]\n\t" \ ++ LSS_BODY_ASM##nr \ ++ "}\n\t" \ ++ "{\n\t" \ ++ " call %%ctpr1, wbs = %#\n\t" \ ++ "}\n\t" \ ++ "{\n\t" \ ++ " addd, s 0x0, %%b[0], %[res]\n\t" \ ++ "}\n\t" \ ++ : [res] "=r" (__res) \ ++ : \ ++ LSS_BODY_ARG##nr(__VA_ARGS__) \ ++ [sys_num] "ri" (__NR_##name) \ ++ : "ctpr1", "ctpr2", "ctpr3", \ ++ "b[0]", "b[1]", "b[2]", "b[3]", \ ++ "b[4]", "b[5]", "b[6]", "b[7]" \ ++ ); \ ++ LSS_RETURN(type, __res); ++ ++ #undef LSS_BODY ++ #define LSS_BODY(nr, type, name, args...) \ ++ _LSS_BODY(nr, type, name, ## args) ++ ++ #undef LSS_BODY_ASM0 ++ #undef LSS_BODY_ASM1 ++ #undef LSS_BODY_ASM2 ++ #undef LSS_BODY_ASM3 ++ #undef LSS_BODY_ASM4 ++ #undef LSS_BODY_ASM5 ++ #undef LSS_BODY_ASM6 ++ ++ #define LSS_BODY_ASM0 ++ #define LSS_BODY_ASM1 LSS_BODY_ASM0 \ ++ " addd, s 0x0, %[arg1], %%b[1]\n\t" ++ #define LSS_BODY_ASM2 LSS_BODY_ASM1 \ ++ " addd, s 0x0, %[arg2], %%b[2]\n\t" ++ #define LSS_BODY_ASM3 LSS_BODY_ASM2 \ ++ " addd, s 0x0, %[arg3], %%b[3]\n\t" ++ #define LSS_BODY_ASM4 LSS_BODY_ASM3 \ ++ " addd, s 0x0, %[arg4], %%b[4]\n\t" ++ #define LSS_BODY_ASM5 LSS_BODY_ASM4 \ ++ " addd, s 0x0, %[arg5], %%b[5]\n\t" ++ #define LSS_BODY_ASM6 LSS_BODY_ASM5 \ ++ "}\n\t" \ ++ "{\n\t" \ ++ " addd, s 0x0, %[arg6], %%b[6]\n\t" ++ ++ #undef LSS_SYSCALL_ARG ++ #define LSS_SYSCALL_ARG(a) ((unsigned long long)(uintptr_t)(a)) ++ ++ #undef LSS_BODY_ARG0 ++ #undef LSS_BODY_ARG1 ++ #undef LSS_BODY_ARG2 ++ #undef LSS_BODY_ARG3 ++ #undef LSS_BODY_ARG4 ++ #undef LSS_BODY_ARG5 ++ #undef LSS_BODY_ARG6 ++ ++ #define LSS_BODY_ARG0() ++ #define LSS_BODY_ARG1(_arg1) \ ++ [arg1] "ri" LSS_SYSCALL_ARG(_arg1), ++ #define LSS_BODY_ARG2(_arg1, _arg2) \ ++ LSS_BODY_ARG1(_arg1) \ ++ [arg2] "ri" LSS_SYSCALL_ARG(_arg2), ++ #define LSS_BODY_ARG3(_arg1, _arg2, _arg3) \ ++ LSS_BODY_ARG2(_arg1, _arg2) \ ++ [arg3] "ri" LSS_SYSCALL_ARG(_arg3), ++ #define LSS_BODY_ARG4(_arg1, _arg2, _arg3, _arg4) \ ++ LSS_BODY_ARG3(_arg1, _arg2, _arg3) \ ++ [arg4] "ri" LSS_SYSCALL_ARG(_arg4), ++ #define LSS_BODY_ARG5(_arg1, _arg2, _arg3, _arg4, _arg5) \ ++ LSS_BODY_ARG4(_arg1, _arg2, _arg3, _arg4) \ ++ [arg5] "ri" LSS_SYSCALL_ARG(_arg5), ++ #define LSS_BODY_ARG6(_arg1, _arg2, _arg3, _arg4, _arg5, _arg6) \ ++ LSS_BODY_ARG5(_arg1, _arg2, _arg3, _arg4, _arg5) \ ++ [arg6] "ri" LSS_SYSCALL_ARG(_arg6), ++ ++ #undef _syscall0 ++ #define _syscall0(type, name) \ ++ type LSS_NAME(name)(void) { \ ++ LSS_BODY(0, type, name); \ ++ } ++ ++ #undef _syscall1 ++ #define _syscall1(type, name, type1, arg1) \ ++ type LSS_NAME(name)(type1 arg1) { \ ++ LSS_BODY(1, type, name, arg1) \ ++ } ++ ++ #undef _syscall2 ++ #define _syscall2(type, name, type1, arg1, type2, arg2) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2) { \ ++ LSS_BODY(2, type, name, arg1, arg2) \ ++ } ++ ++ #undef _syscall3 ++ #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ ++ LSS_BODY(3, type, name, arg1, arg2, arg3) \ ++ } ++ ++ #undef _syscall4 ++ #define _syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \ ++ type4, arg4) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ ++ LSS_BODY(4, type, name, arg1, arg2, arg3, arg4) \ ++ } ++ ++ #undef _syscall5 ++ #define _syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \ ++ type4, arg4, type5, arg5) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5) { \ ++ LSS_BODY(5, type, name, arg1, arg2, arg3, arg4, arg5) \ ++ } ++ ++ #undef _syscall6 ++ #define _syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \ ++ type4, arg4, type5, arg5, type6, arg6) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5, type6 arg6) { \ ++ LSS_BODY(6, type, name, arg1, arg2, arg3, arg4, arg5, arg6) \ ++ } ++ ++ LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, ++ int flags, void *arg, int *parent_tidptr, ++ void *newtls, int *child_tidptr) { ++ unsigned long long __res; ++ ++ __asm__ __volatile__ ( ++ "{\n\t" ++ " addd,s 0x0, %[nr_clone], %%b[0]\n\t" ++ " addd,s 0x0, %[flags], %%db[1]\n\t" ++ " addd,s 0x0, %[child_stack], %%db[2]\n\t" ++ " addd,s 0x0, %[parent_tidptr], %%db[3]\n\t" ++ " addd,s 0x0, %[child_tidptr], %%db[4]\n\t" ++ " addd,s 0x0, %[newtls], %%db[5]\n\t" ++ "}\n\t" ++ /* if (fn == NULL) ++ * return -EINVAL; ++ */ ++ ++ "{\n\t" ++ " disp %%ctpr1, .L1\n\t" ++ "}\n\t" ++ "{\n\t" ++ " cmpesb,s 0x0, %[fn], %%pred0\n\t" ++ "}\n\t" ++ "{\n\t" ++ " ct %%ctpr1 ? %%pred0\n\t" ++ "}\n\t" ++ ++ /* if (child_stack == NULL) ++ * return -EINVAL; ++ */ ++ "{\n\t" ++ " cmpesb,s 0x0, %%db[2], %%pred0\n\t" ++ "}\n\t" ++ "{\n\t" ++ " ct %%ctpr1 ? %%pred0\n\t" ++ "}\n\t" ++ ++ /* b[0] = syscall(%b[0] = __NR_clone, ++ * %db[1] = flags, ++ * %db[2] = child_stack, ++ * %db[3] = parent_tidptr, ++ * %db[4] = child_tidptr, ++ * %db[5] = newtls) ++ */ ++ "{\n\t" ++ " sdisp %%ctpr1, 0x3\n\t" ++ "}\n\t" ++ "{\n\t" ++ " call %%ctpr1, wbs = %#\n\t" ++ "}\n\t" ++ ++ /* if (%[b0] != 0) ++ * return %b[0]; ++ */ ++ "{\n\t" ++ " disp %%ctpr1, .L2\n\t" ++ " cmpesb,s 0x0, %%b[0], %%pred0\n\t" ++ "}\n\t" ++ "{\n\t" ++ " ct %%ctpr1 ? ~%%pred0\n\t" ++ "}\n\t" ++ /* In the child, now. Call "fn(arg)". ++ */ ++ ++ "{\n\t" ++ " movtd,s %[fn], %%ctpr1\n\t" ++ "}\n\t" ++ "{\n\t" ++ " addd,s 0x0, %[arg], %%db[0]\n\t" ++ "}\n\t" ++ "{\n\t" ++ " call %%ctpr1, wbs = %#\n\t" ++ "}\n\t" ++ /* Call _exit(%b[0]). ++ */ ++ ++ "{\n\t" ++ " sdisp %%ctpr1, 0x3\n\t" ++ " addd,s 0x0, %%b[0], %%b[1]\n\t" ++ "}\n\t" ++ "{\n\t" ++ " addd,s 0x0, %[nr_exit], %%b[0]\n\t" ++ "}\n\t" ++ "{\n\t" ++ " call %%ctpr1, wbs = %#\n\t" ++ "}\n\t" ++ "{\n\t" ++ " disp %%ctpr1, .L2\n\t" ++ " adds,s 0x0, 0x0, %%b[0]\n\t" ++ "}\n\t" ++ "{\n\t" ++ " ct %%ctpr1\n\t" ++ "}\n\t" ++ ".L1:\n\t" ++ "{\n\t" ++ " addd,s 0x0, %[einval], %%b[0]\n\t" ++ "}\n\t" ++ ".L2:\n\t" ++ "{\n\t" ++ " addd,s 0x0, %%b[0], %[res]\n\t" ++ "}\n\t" ++ : [res] "=r" LSS_SYSCALL_ARG(__res) ++ : [nr_clone] "ri" LSS_SYSCALL_ARG(__NR_clone) ++ [arg] "ri" LSS_SYSCALL_ARG(arg) ++ [nr_exit] "ri" LSS_SYSCALL_ARG(__NR_exit) ++ [flags] "ri" LSS_SYSCALL_ARG(flags) ++ [child_stack] "ri" LSS_SYSCALL_ARG(child_stack) ++ [parent_tidptr] "ri" ++ LSS_SYSCALL_ARG(parent_tidptr) ++ [newtls] "ri" LSS_SYSCALL_ARG(newtls) ++ [child_tidptr] "ri" ++ LSS_SYSCALL_ARG(child_tidptr) ++ [fn] "ri" LSS_SYSCALL_ARG(fn) ++ [einval] "ri" LSS_SYSCALL_ARG(-EINVAL) ++ : "ctpr1", "b[0]", "b[1]", "b[2]", "b[3]", ++ "b[4]", "b[5]", "pred0"); ++ LSS_RETURN(int, __res); ++ } ++ #elif defined(__loongarch_lp64) ++ /* Most definitions of _syscallX() neglect to mark "memory" as being ++ * clobbered. This causes problems with compilers, that do a better job ++ * at optimizing across __asm__ calls. ++ * So, we just have to redefine all of the _syscallX() macros. ++ */ ++ #undef LSS_REG ++ #define LSS_REG(ar,a) register int64_t __r##ar __asm__("a"#ar) = (int64_t)a ++ /* syscall is like subroutine calls, all caller-saved registers may be ++ * clobbered, we should add them to the |Clobbers| list. ++ * a0 is not included because it's in the output list. ++ */ ++ #define LSS_SYSCALL_CLOBBERS "t0", "t1", "t2", "t3", "t4", "t5", "t6", \ ++ "t7", "t8", "memory" ++ #undef LSS_BODY ++ #define LSS_BODY(type,name,args...) \ ++ register int64_t __res_a0 __asm__("a0"); \ ++ register int64_t __a7 __asm__("a7") = __NR_##name; \ ++ int64_t __res; \ ++ __asm__ __volatile__ ("syscall 0x0\n" \ ++ : "=r"(__res_a0) \ ++ : "r"(__a7), ## args \ ++ : LSS_SYSCALL_CLOBBERS); \ ++ __res = __res_a0; \ ++ LSS_RETURN(type, __res) ++ #undef _syscall0 ++ #define _syscall0(type, name) \ ++ type LSS_NAME(name)(void) { \ ++ LSS_BODY(type, name); \ ++ } ++ #undef _syscall1 ++ #define _syscall1(type, name, type1, arg1) \ ++ type LSS_NAME(name)(type1 arg1) { \ ++ LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ ++ } ++ #undef _syscall2 ++ #define _syscall2(type, name, type1, arg1, type2, arg2) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ ++ } ++ #undef _syscall3 ++ #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ ++ } ++ #undef _syscall4 ++ #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_REG(3, arg4); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ ++ } ++ #undef _syscall5 ++ #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_REG(3, arg4); LSS_REG(4, arg5); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ ++ "r"(__r4)); \ ++ } ++ #undef _syscall6 ++ #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ ++ type5,arg5,type6,arg6) \ ++ type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ ++ type5 arg5, type6 arg6) { \ ++ LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ ++ LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ ++ LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ ++ "r"(__r4), "r"(__r5)); \ ++ } ++ ++ LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, ++ int flags, void *arg, int *parent_tidptr, ++ void *newtls, int *child_tidptr) { ++ int64_t __res; ++ { ++ register int64_t __res_a0 __asm__("a0"); ++ register uint64_t __flags __asm__("a0") = flags; ++ register void *__stack __asm__("a1") = child_stack; ++ register void *__ptid __asm__("a2") = parent_tidptr; ++ register void *__tls __asm__("a3") = newtls; ++ register int *__ctid __asm__("a4") = child_tidptr; ++ __asm__ __volatile__(/* Push "arg" and "fn" onto the stack that will be ++ * used by the child. ++ */ ++ "addi.d %2, %2, -16\n" ++ "st.d %1, %2, 8\n" ++ "st.d %4, %2, 0\n" ++ ++ /* %a0 = syscall(%a0 = flags, ++ * %a1 = child_stack, ++ * %a2 = parent_tidptr, ++ * %a3 = newtls, ++ * %a4 = child_tidptr) ++ */ ++ "li.d $a7, %8\n" ++ "syscall 0x0\n" ++ ++ /* if (%a0 != 0) ++ * return %a0; ++ */ ++ "bnez $a0, 1f\n" ++ ++ /* In the child, now. Call "fn(arg)". ++ */ ++ "ld.d $a0, $sp, 0\n" ++ "ld.d $a1, $sp, 8\n" ++ "addi.d $sp, $sp, 16\n" ++ "jirl $ra, $a1, 0\n" ++ ++ /* Call _exit(%a0). ++ */ ++ "li.d $a7, %9\n" ++ "syscall 0x0\n" ++ "1:\n" ++ : "=r" (__res_a0) ++ : "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), ++ "r"(__ptid), "r"(__tls), "r"(__ctid), ++ "i"(__NR_clone), "i"(__NR_exit) ++ : "a7", LSS_SYSCALL_CLOBBERS); ++ __res = __res_a0; ++ } ++ LSS_RETURN(int, __res); ++ } ++ ++ #endif ++ #define __NR__exit __NR_exit ++ #define __NR__gettid __NR_gettid ++ #define __NR__mremap __NR_mremap ++ LSS_INLINE _syscall1(void *, brk, void *, e) ++ LSS_INLINE _syscall1(int, chdir, const char *,p) ++ LSS_INLINE _syscall1(int, close, int, f) ++ LSS_INLINE _syscall2(int, clock_getres, int, c, ++ struct kernel_timespec*, t) ++ LSS_INLINE _syscall2(int, clock_gettime, int, c, ++ struct kernel_timespec*, t) ++ LSS_INLINE _syscall1(int, dup, int, f) ++ #if defined(__NR_dup2) ++ // dup2 is polyfilled below when not available. ++ LSS_INLINE _syscall2(int, dup2, int, s, ++ int, d) ++ #endif ++ #if defined(__NR_dup3) ++ LSS_INLINE _syscall3(int, dup3, int, s, int, d, int, f) ++ #endif ++ LSS_INLINE _syscall3(int, execve, const char*, f, ++ const char*const*,a,const char*const*, e) ++ LSS_INLINE _syscall1(int, _exit, int, e) ++ LSS_INLINE _syscall1(int, exit_group, int, e) ++ LSS_INLINE _syscall3(int, fcntl, int, f, ++ int, c, long, a) ++ #if defined(__NR_fork) ++ // fork is polyfilled below when not available. ++ LSS_INLINE _syscall0(pid_t, fork) ++ #endif ++ #if defined(__NR_fstat) ++ LSS_INLINE _syscall2(int, fstat, int, f, ++ struct kernel_stat*, b) ++ #endif ++ LSS_INLINE _syscall2(int, fstatfs, int, f, ++ struct kernel_statfs*, b) ++ #if defined(__x86_64__) ++ /* Need to make sure off_t isn't truncated to 32-bits under x32. */ ++ LSS_INLINE int LSS_NAME(ftruncate)(int f, off_t l) { ++ LSS_BODY(2, int, ftruncate, LSS_SYSCALL_ARG(f), (uint64_t)(l)); ++ } ++ #else ++ LSS_INLINE _syscall2(int, ftruncate, int, f, ++ off_t, l) ++ #endif ++ LSS_INLINE _syscall6(int, futex, int*, u, ++ int, o, int, v, ++ struct kernel_timespec*, t, ++ int*, u2, int, v2) ++ LSS_INLINE _syscall3(int, getdents, int, f, ++ struct kernel_dirent*, d, int, c) ++ LSS_INLINE _syscall3(int, getdents64, int, f, ++ struct kernel_dirent64*, d, int, c) ++ LSS_INLINE _syscall0(gid_t, getegid) ++ LSS_INLINE _syscall0(uid_t, geteuid) ++ LSS_INLINE _syscall2(int, getitimer, int, w, ++ struct kernel_itimerval*, c) ++ #if defined(__NR_getpgrp) ++ LSS_INLINE _syscall0(pid_t, getpgrp) ++ #endif ++ LSS_INLINE _syscall0(pid_t, getpid) ++ LSS_INLINE _syscall0(pid_t, getppid) ++ LSS_INLINE _syscall2(int, getpriority, int, a, ++ int, b) ++ LSS_INLINE _syscall3(int, getresgid, gid_t *, r, ++ gid_t *, e, gid_t *, s) ++ LSS_INLINE _syscall3(int, getresuid, uid_t *, r, ++ uid_t *, e, uid_t *, s) ++ #if defined(__NR_getrlimit) ++ LSS_INLINE _syscall2(int, getrlimit, int, r, ++ struct kernel_rlimit*, l) ++ #endif ++ LSS_INLINE _syscall1(pid_t, getsid, pid_t, p) ++ LSS_INLINE _syscall0(pid_t, _gettid) ++ LSS_INLINE _syscall2(pid_t, gettimeofday, struct kernel_timeval*, t, ++ void*, tz) ++ LSS_INLINE _syscall5(int, setxattr, const char *,p, ++ const char *, n, const void *,v, ++ size_t, s, int, f) ++ LSS_INLINE _syscall5(int, lsetxattr, const char *,p, ++ const char *, n, const void *,v, ++ size_t, s, int, f) ++ LSS_INLINE _syscall4(ssize_t, getxattr, const char *,p, ++ const char *, n, void *, v, size_t, s) ++ LSS_INLINE _syscall4(ssize_t, lgetxattr, const char *,p, ++ const char *, n, void *, v, size_t, s) ++ LSS_INLINE _syscall3(ssize_t, listxattr, const char *,p, ++ char *, l, size_t, s) ++ LSS_INLINE _syscall3(ssize_t, llistxattr, const char *,p, ++ char *, l, size_t, s) ++ LSS_INLINE _syscall3(int, ioctl, int, d, ++ int, r, void *, a) ++ LSS_INLINE _syscall2(int, ioprio_get, int, which, ++ int, who) ++ LSS_INLINE _syscall3(int, ioprio_set, int, which, ++ int, who, int, ioprio) ++ LSS_INLINE _syscall2(int, kill, pid_t, p, ++ int, s) ++ #if defined(__x86_64__) ++ /* Need to make sure off_t isn't truncated to 32-bits under x32. */ ++ LSS_INLINE off_t LSS_NAME(lseek)(int f, off_t o, int w) { ++ _LSS_BODY(3, off_t, lseek, off_t, LSS_SYSCALL_ARG(f), (uint64_t)(o), ++ LSS_SYSCALL_ARG(w)); ++ } ++ #else ++ LSS_INLINE _syscall3(off_t, lseek, int, f, ++ off_t, o, int, w) ++ #endif ++ LSS_INLINE _syscall2(int, munmap, void*, s, ++ size_t, l) ++ LSS_INLINE _syscall6(long, move_pages, pid_t, p, ++ unsigned long, n, void **,g, int *, d, ++ int *, s, int, f) ++ LSS_INLINE _syscall3(int, mprotect, const void *,a, ++ size_t, l, int, p) ++ LSS_INLINE _syscall5(void*, _mremap, void*, o, ++ size_t, os, size_t, ns, ++ unsigned long, f, void *, a) ++ #if defined(__NR_open) ++ // open is polyfilled below when not available. ++ LSS_INLINE _syscall3(int, open, const char*, p, ++ int, f, int, m) ++ #endif ++ #if defined(__NR_poll) ++ // poll is polyfilled below when not available. ++ LSS_INLINE _syscall3(int, poll, struct kernel_pollfd*, u, ++ unsigned int, n, int, t) ++ #endif ++ #if defined(__NR_ppoll) ++ LSS_INLINE _syscall5(int, ppoll, struct kernel_pollfd *, u, ++ unsigned int, n, const struct kernel_timespec *, t, ++ const struct kernel_sigset_t *, sigmask, size_t, s) ++ #endif ++ LSS_INLINE _syscall5(int, prctl, int, option, ++ unsigned long, arg2, ++ unsigned long, arg3, ++ unsigned long, arg4, ++ unsigned long, arg5) ++ LSS_INLINE _syscall4(long, ptrace, int, r, ++ pid_t, p, void *, a, void *, d) ++ #if defined(__NR_quotactl) ++ // Defined on x86_64 / i386 only ++ LSS_INLINE _syscall4(int, quotactl, int, cmd, const char *, special, ++ int, id, caddr_t, addr) ++ #endif ++ LSS_INLINE _syscall3(ssize_t, read, int, f, ++ void *, b, size_t, c) ++ #if defined(__NR_readlink) ++ // readlink is polyfilled below when not available. ++ LSS_INLINE _syscall3(int, readlink, const char*, p, ++ char*, b, size_t, s) ++ #endif ++ #if defined(__NR_readlinkat) ++ LSS_INLINE _syscall4(int, readlinkat, int, d, const char *, p, char *, b, ++ size_t, s) ++ #endif ++ LSS_INLINE _syscall4(int, rt_sigaction, int, s, ++ const struct kernel_sigaction*, a, ++ struct kernel_sigaction*, o, size_t, c) ++ LSS_INLINE _syscall2(int, rt_sigpending, struct kernel_sigset_t *, s, ++ size_t, c) ++ LSS_INLINE _syscall4(int, rt_sigprocmask, int, h, ++ const struct kernel_sigset_t*, s, ++ struct kernel_sigset_t*, o, size_t, c) ++ LSS_INLINE _syscall2(int, rt_sigsuspend, ++ const struct kernel_sigset_t*, s, size_t, c) ++ LSS_INLINE _syscall4(int, rt_sigtimedwait, const struct kernel_sigset_t*, s, ++ siginfo_t*, i, const struct timespec*, t, size_t, c) ++ LSS_INLINE _syscall3(int, sched_getaffinity,pid_t, p, ++ unsigned int, l, unsigned long *, m) ++ LSS_INLINE _syscall3(int, sched_setaffinity,pid_t, p, ++ unsigned int, l, unsigned long *, m) ++ LSS_INLINE _syscall0(int, sched_yield) ++ LSS_INLINE _syscall1(long, set_tid_address, int *, t) ++ LSS_INLINE _syscall1(int, setfsgid, gid_t, g) ++ LSS_INLINE _syscall1(int, setfsuid, uid_t, u) ++ LSS_INLINE _syscall1(int, setuid, uid_t, u) ++ LSS_INLINE _syscall1(int, setgid, gid_t, g) ++ LSS_INLINE _syscall3(int, setitimer, int, w, ++ const struct kernel_itimerval*, n, ++ struct kernel_itimerval*, o) ++ LSS_INLINE _syscall2(int, setpgid, pid_t, p, ++ pid_t, g) ++ LSS_INLINE _syscall3(int, setpriority, int, a, ++ int, b, int, p) ++ LSS_INLINE _syscall3(int, setresgid, gid_t, r, ++ gid_t, e, gid_t, s) ++ LSS_INLINE _syscall3(int, setresuid, uid_t, r, ++ uid_t, e, uid_t, s) ++ #if defined(__NR_setrlimit) ++ LSS_INLINE _syscall2(int, setrlimit, int, r, ++ const struct kernel_rlimit*, l) ++ #endif ++ LSS_INLINE _syscall0(pid_t, setsid) ++ LSS_INLINE _syscall2(int, sigaltstack, const stack_t*, s, ++ const stack_t*, o) ++ #if defined(__NR_sigreturn) ++ LSS_INLINE _syscall1(int, sigreturn, unsigned long, u) ++ #endif ++ #if defined(__NR_stat) ++ // stat and lstat are polyfilled below when not available. ++ LSS_INLINE _syscall2(int, stat, const char*, f, ++ struct kernel_stat*, b) ++ #endif ++ #if defined(__NR_lstat) ++ LSS_INLINE _syscall2(int, lstat, const char*, f, ++ struct kernel_stat*, b) ++ #endif ++ LSS_INLINE _syscall2(int, statfs, const char*, f, ++ struct kernel_statfs*, b) ++ LSS_INLINE _syscall3(int, tgkill, pid_t, p, ++ pid_t, t, int, s) ++ LSS_INLINE _syscall2(int, tkill, pid_t, p, ++ int, s) ++ #if defined(__NR_unlink) ++ // unlink is polyfilled below when not available. ++ LSS_INLINE _syscall1(int, unlink, const char*, f) ++ #endif ++ LSS_INLINE _syscall3(ssize_t, write, int, f, ++ const void *, b, size_t, c) ++ LSS_INLINE _syscall3(ssize_t, writev, int, f, ++ const struct kernel_iovec*, v, size_t, c) ++ #if defined(__NR_getcpu) ++ LSS_INLINE _syscall3(long, getcpu, unsigned *, cpu, ++ unsigned *, node, void *, unused) ++ #endif ++ #if defined(__NR_fadvise64) ++ #if defined(__x86_64__) ++ /* Need to make sure loff_t isn't truncated to 32-bits under x32. */ ++ LSS_INLINE int LSS_NAME(fadvise64)(int fd, loff_t offset, loff_t len, ++ int advice) { ++ LSS_BODY(4, int, fadvise64, LSS_SYSCALL_ARG(fd), (uint64_t)(offset), ++ (uint64_t)(len), LSS_SYSCALL_ARG(advice)); ++ } ++ #else ++ LSS_INLINE _syscall4(int, fadvise64, ++ int, fd, loff_t, offset, loff_t, len, int, advice) ++ #endif ++ #elif defined(__i386__) ++ #define __NR__fadvise64_64 __NR_fadvise64_64 ++ LSS_INLINE _syscall6(int, _fadvise64_64, int, fd, ++ unsigned, offset_lo, unsigned, offset_hi, ++ unsigned, len_lo, unsigned, len_hi, ++ int, advice) ++ ++ LSS_INLINE int LSS_NAME(fadvise64)(int fd, loff_t offset, ++ loff_t len, int advice) { ++ return LSS_NAME(_fadvise64_64)(fd, ++ (unsigned)offset, (unsigned)(offset >>32), ++ (unsigned)len, (unsigned)(len >> 32), ++ advice); ++ } ++ ++ #elif defined(__s390__) && !defined(__s390x__) ++ #define __NR__fadvise64_64 __NR_fadvise64_64 ++ struct kernel_fadvise64_64_args { ++ int fd; ++ long long offset; ++ long long len; ++ int advice; ++ }; ++ ++ LSS_INLINE _syscall1(int, _fadvise64_64, ++ struct kernel_fadvise64_64_args *args) ++ ++ LSS_INLINE int LSS_NAME(fadvise64)(int fd, loff_t offset, ++ loff_t len, int advice) { ++ struct kernel_fadvise64_64_args args = { fd, offset, len, advice }; ++ return LSS_NAME(_fadvise64_64)(&args); ++ } ++ #endif ++ #if defined(__NR_fallocate) ++ #if defined(__x86_64__) ++ /* Need to make sure loff_t isn't truncated to 32-bits under x32. */ ++ LSS_INLINE int LSS_NAME(fallocate)(int f, int mode, loff_t offset, ++ loff_t len) { ++ LSS_BODY(4, int, fallocate, LSS_SYSCALL_ARG(f), LSS_SYSCALL_ARG(mode), ++ (uint64_t)(offset), (uint64_t)(len)); ++ } ++ #elif (defined(__i386__) || (defined(__s390__) && !defined(__s390x__)) \ ++ || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) \ ++ || (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) \ ++ || defined(__PPC__)) ++ #define __NR__fallocate __NR_fallocate ++ LSS_INLINE _syscall6(int, _fallocate, int, fd, ++ int, mode, ++ unsigned, offset_lo, unsigned, offset_hi, ++ unsigned, len_lo, unsigned, len_hi) ++ ++ LSS_INLINE int LSS_NAME(fallocate)(int fd, int mode, ++ loff_t offset, loff_t len) { ++ union { loff_t off; unsigned w[2]; } o = { offset }, l = { len }; ++ return LSS_NAME(_fallocate)(fd, mode, o.w[0], o.w[1], l.w[0], l.w[1]); ++ } ++ #else ++ LSS_INLINE _syscall4(int, fallocate, ++ int, f, int, mode, loff_t, offset, loff_t, len) ++ #endif ++ #endif ++ #if defined(__NR_getrandom) ++ LSS_INLINE _syscall3(ssize_t, getrandom, void*, buffer, size_t, length, ++ unsigned int, flags) ++ #endif ++ #if defined(__NR_newfstatat) ++ LSS_INLINE _syscall4(int, newfstatat, int, d, ++ const char *, p, ++ struct kernel_stat*, b, int, f) ++ #endif ++ #if defined(__NR_statx) ++ LSS_INLINE _syscall5(int, statx, int, d, ++ const char *, p, ++ int, f, int, m, ++ struct kernel_statx*, b) ++ #endif ++ #if defined(__x86_64__) || defined(__s390x__) ++ LSS_INLINE int LSS_NAME(getresgid32)(gid_t *rgid, ++ gid_t *egid, ++ gid_t *sgid) { ++ return LSS_NAME(getresgid)(rgid, egid, sgid); ++ } ++ ++ LSS_INLINE int LSS_NAME(getresuid32)(uid_t *ruid, ++ uid_t *euid, ++ uid_t *suid) { ++ return LSS_NAME(getresuid)(ruid, euid, suid); ++ } ++ ++ LSS_INLINE int LSS_NAME(setfsgid32)(gid_t gid) { ++ return LSS_NAME(setfsgid)(gid); ++ } ++ ++ LSS_INLINE int LSS_NAME(setfsuid32)(uid_t uid) { ++ return LSS_NAME(setfsuid)(uid); ++ } ++ ++ LSS_INLINE int LSS_NAME(setresgid32)(gid_t rgid, gid_t egid, gid_t sgid) { ++ return LSS_NAME(setresgid)(rgid, egid, sgid); ++ } ++ ++ LSS_INLINE int LSS_NAME(setresuid32)(uid_t ruid, uid_t euid, uid_t suid) { ++ return LSS_NAME(setresuid)(ruid, euid, suid); ++ } ++ ++ LSS_INLINE int LSS_NAME(sigaction)(int signum, ++ const struct kernel_sigaction *act, ++ struct kernel_sigaction *oldact) { ++ #if defined(__x86_64__) ++ /* On x86_64, the kernel requires us to always set our own ++ * SA_RESTORER in order to be able to return from a signal handler. ++ * This function must have a "magic" signature that the "gdb" ++ * (and maybe the kernel?) can recognize. ++ */ ++ if (act != NULL && !(act->sa_flags & SA_RESTORER)) { ++ struct kernel_sigaction a = *act; ++ a.sa_flags |= SA_RESTORER; ++ a.sa_restorer = LSS_NAME(restore_rt)(); ++ return LSS_NAME(rt_sigaction)(signum, &a, oldact, ++ (KERNEL_NSIG+7)/8); ++ } else ++ #endif ++ return LSS_NAME(rt_sigaction)(signum, act, oldact, ++ (KERNEL_NSIG+7)/8); ++ } ++ ++ LSS_INLINE int LSS_NAME(sigpending)(struct kernel_sigset_t *set) { ++ return LSS_NAME(rt_sigpending)(set, (KERNEL_NSIG+7)/8); ++ } ++ ++ LSS_INLINE int LSS_NAME(sigsuspend)(const struct kernel_sigset_t *set) { ++ return LSS_NAME(rt_sigsuspend)(set, (KERNEL_NSIG+7)/8); ++ } ++ #endif ++ #if defined(__NR_rt_sigprocmask) ++ LSS_INLINE int LSS_NAME(sigprocmask)(int how, ++ const struct kernel_sigset_t *set, ++ struct kernel_sigset_t *oldset) { ++ return LSS_NAME(rt_sigprocmask)(how, set, oldset, (KERNEL_NSIG+7)/8); ++ } ++ #endif ++ #if defined(__NR_rt_sigtimedwait) ++ LSS_INLINE int LSS_NAME(sigtimedwait)(const struct kernel_sigset_t *set, ++ siginfo_t *info, ++ const struct timespec *timeout) { ++ return LSS_NAME(rt_sigtimedwait)(set, info, timeout, (KERNEL_NSIG+7)/8); ++ } ++ #endif ++ #if defined(__NR_wait4) ++ LSS_INLINE _syscall4(pid_t, wait4, pid_t, p, ++ int*, s, int, o, ++ struct kernel_rusage*, r) ++ #endif ++ #if defined(__NR_openat) ++ LSS_INLINE _syscall4(int, openat, int, d, const char *, p, int, f, int, m) ++ #endif ++ #if defined(__NR_unlinkat) ++ LSS_INLINE _syscall3(int, unlinkat, int, d, const char *, p, int, f) ++ #endif ++ #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ ++ (defined(__s390__) && !defined(__s390x__)) ++ #define __NR__getresgid32 __NR_getresgid32 ++ #define __NR__getresuid32 __NR_getresuid32 ++ #define __NR__setfsgid32 __NR_setfsgid32 ++ #define __NR__setfsuid32 __NR_setfsuid32 ++ #define __NR__setresgid32 __NR_setresgid32 ++ #define __NR__setresuid32 __NR_setresuid32 ++#if defined(__ARM_EABI__) ++ LSS_INLINE _syscall2(int, ugetrlimit, int, r, ++ struct kernel_rlimit*, l) ++#endif ++ LSS_INLINE _syscall3(int, _getresgid32, gid_t *, r, ++ gid_t *, e, gid_t *, s) ++ LSS_INLINE _syscall3(int, _getresuid32, uid_t *, r, ++ uid_t *, e, uid_t *, s) ++ LSS_INLINE _syscall1(int, _setfsgid32, gid_t, f) ++ LSS_INLINE _syscall1(int, _setfsuid32, uid_t, f) ++ LSS_INLINE _syscall3(int, _setresgid32, gid_t, r, ++ gid_t, e, gid_t, s) ++ LSS_INLINE _syscall3(int, _setresuid32, uid_t, r, ++ uid_t, e, uid_t, s) ++ ++ LSS_INLINE int LSS_NAME(getresgid32)(gid_t *rgid, ++ gid_t *egid, ++ gid_t *sgid) { ++ int rc; ++ if ((rc = LSS_NAME(_getresgid32)(rgid, egid, sgid)) < 0 && ++ LSS_ERRNO == ENOSYS) { ++ if ((rgid == NULL) || (egid == NULL) || (sgid == NULL)) { ++ return EFAULT; ++ } ++ // Clear the high bits first, since getresgid only sets 16 bits ++ *rgid = *egid = *sgid = 0; ++ rc = LSS_NAME(getresgid)(rgid, egid, sgid); ++ } ++ return rc; ++ } ++ ++ LSS_INLINE int LSS_NAME(getresuid32)(uid_t *ruid, ++ uid_t *euid, ++ uid_t *suid) { ++ int rc; ++ if ((rc = LSS_NAME(_getresuid32)(ruid, euid, suid)) < 0 && ++ LSS_ERRNO == ENOSYS) { ++ if ((ruid == NULL) || (euid == NULL) || (suid == NULL)) { ++ return EFAULT; ++ } ++ // Clear the high bits first, since getresuid only sets 16 bits ++ *ruid = *euid = *suid = 0; ++ rc = LSS_NAME(getresuid)(ruid, euid, suid); ++ } ++ return rc; ++ } ++ ++ LSS_INLINE int LSS_NAME(setfsgid32)(gid_t gid) { ++ int rc; ++ if ((rc = LSS_NAME(_setfsgid32)(gid)) < 0 && ++ LSS_ERRNO == ENOSYS) { ++ if ((unsigned int)gid & ~0xFFFFu) { ++ rc = EINVAL; ++ } else { ++ rc = LSS_NAME(setfsgid)(gid); ++ } ++ } ++ return rc; ++ } ++ ++ LSS_INLINE int LSS_NAME(setfsuid32)(uid_t uid) { ++ int rc; ++ if ((rc = LSS_NAME(_setfsuid32)(uid)) < 0 && ++ LSS_ERRNO == ENOSYS) { ++ if ((unsigned int)uid & ~0xFFFFu) { ++ rc = EINVAL; ++ } else { ++ rc = LSS_NAME(setfsuid)(uid); ++ } ++ } ++ return rc; ++ } ++ ++ LSS_INLINE int LSS_NAME(setresgid32)(gid_t rgid, gid_t egid, gid_t sgid) { ++ int rc; ++ if ((rc = LSS_NAME(_setresgid32)(rgid, egid, sgid)) < 0 && ++ LSS_ERRNO == ENOSYS) { ++ if ((unsigned int)rgid & ~0xFFFFu || ++ (unsigned int)egid & ~0xFFFFu || ++ (unsigned int)sgid & ~0xFFFFu) { ++ rc = EINVAL; ++ } else { ++ rc = LSS_NAME(setresgid)(rgid, egid, sgid); ++ } ++ } ++ return rc; ++ } ++ ++ LSS_INLINE int LSS_NAME(setresuid32)(uid_t ruid, uid_t euid, uid_t suid) { ++ int rc; ++ if ((rc = LSS_NAME(_setresuid32)(ruid, euid, suid)) < 0 && ++ LSS_ERRNO == ENOSYS) { ++ if ((unsigned int)ruid & ~0xFFFFu || ++ (unsigned int)euid & ~0xFFFFu || ++ (unsigned int)suid & ~0xFFFFu) { ++ rc = EINVAL; ++ } else { ++ rc = LSS_NAME(setresuid)(ruid, euid, suid); ++ } ++ } ++ return rc; ++ } ++ #endif ++ LSS_INLINE int LSS_NAME(sigemptyset)(struct kernel_sigset_t *set) { ++ memset(&set->sig, 0, sizeof(set->sig)); ++ return 0; ++ } ++ ++ LSS_INLINE int LSS_NAME(sigfillset)(struct kernel_sigset_t *set) { ++ memset(&set->sig, -1, sizeof(set->sig)); ++ return 0; ++ } ++ ++ LSS_INLINE int LSS_NAME(sigaddset)(struct kernel_sigset_t *set, ++ int signum) { ++ if (signum < 1 || (size_t)signum > (8*sizeof(set->sig))) { ++ LSS_ERRNO = EINVAL; ++ return -1; ++ } else { ++ set->sig[(size_t)(signum - 1)/(8*sizeof(set->sig[0]))] ++ |= 1UL << ((size_t)(signum - 1) % (8*sizeof(set->sig[0]))); ++ return 0; ++ } ++ } ++ ++ LSS_INLINE int LSS_NAME(sigdelset)(struct kernel_sigset_t *set, ++ int signum) { ++ if (signum < 1 || (size_t)signum > (8*sizeof(set->sig))) { ++ LSS_ERRNO = EINVAL; ++ return -1; ++ } else { ++ set->sig[(size_t)(signum - 1)/(8*sizeof(set->sig[0]))] ++ &= ~(1UL << ((size_t)(signum - 1) % (8*sizeof(set->sig[0])))); ++ return 0; ++ } ++ } ++ ++ LSS_INLINE int LSS_NAME(sigismember)(struct kernel_sigset_t *set, ++ int signum) { ++ if (signum < 1 || (size_t)signum > (8*sizeof(set->sig))) { ++ LSS_ERRNO = EINVAL; ++ return -1; ++ } else { ++ return !!(set->sig[(size_t)(signum - 1)/(8*sizeof(set->sig[0]))] & ++ (1UL << ((size_t)(signum - 1) % (8*sizeof(set->sig[0]))))); ++ } ++ } ++ #if defined(__i386__) || \ ++ defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ ++ (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ ++ defined(__PPC__) || \ ++ (defined(__s390__) && !defined(__s390x__)) || defined(__e2k__) ++ #define __NR__sigaction __NR_sigaction ++ #define __NR__sigpending __NR_sigpending ++ #define __NR__sigsuspend __NR_sigsuspend ++ #define __NR__socketcall __NR_socketcall ++ LSS_INLINE _syscall2(int, fstat64, int, f, ++ struct kernel_stat64 *, b) ++ LSS_INLINE _syscall5(int, _llseek, uint, fd, ++ unsigned long, hi, unsigned long, lo, ++ loff_t *, res, uint, wh) ++#if defined(__s390__) && !defined(__s390x__) ++ /* On s390, mmap2() arguments are passed in memory. */ ++ LSS_INLINE void* LSS_NAME(_mmap2)(void *s, size_t l, int p, int f, int d, ++ off_t o) { ++ unsigned long buf[6] = { (unsigned long) s, (unsigned long) l, ++ (unsigned long) p, (unsigned long) f, ++ (unsigned long) d, (unsigned long) o }; ++ LSS_REG(2, buf); ++ LSS_BODY(void*, mmap2, "0"(__r2)); ++ } ++#else ++ #define __NR__mmap2 __NR_mmap2 ++ LSS_INLINE _syscall6(void*, _mmap2, void*, s, ++ size_t, l, int, p, ++ int, f, int, d, ++ off_t, o) ++#endif ++ LSS_INLINE _syscall3(int, _sigaction, int, s, ++ const struct kernel_old_sigaction*, a, ++ struct kernel_old_sigaction*, o) ++ LSS_INLINE _syscall1(int, _sigpending, unsigned long*, s) ++ #ifdef __PPC__ ++ LSS_INLINE _syscall1(int, _sigsuspend, unsigned long, s) ++ #else ++ LSS_INLINE _syscall3(int, _sigsuspend, const void*, a, ++ int, b, ++ unsigned long, s) ++ #endif ++ LSS_INLINE _syscall2(int, stat64, const char *, p, ++ struct kernel_stat64 *, b) ++ ++ LSS_INLINE int LSS_NAME(sigaction)(int signum, ++ const struct kernel_sigaction *act, ++ struct kernel_sigaction *oldact) { ++ int old_errno = LSS_ERRNO; ++ int rc; ++ struct kernel_sigaction a; ++ if (act != NULL) { ++ a = *act; ++ #ifdef __i386__ ++ /* On i386, the kernel requires us to always set our own ++ * SA_RESTORER when using realtime signals. Otherwise, it does not ++ * know how to return from a signal handler. This function must have ++ * a "magic" signature that the "gdb" (and maybe the kernel?) can ++ * recognize. ++ * Apparently, a SA_RESTORER is implicitly set by the kernel, when ++ * using non-realtime signals. ++ * ++ * TODO: Test whether ARM needs a restorer ++ */ ++ if (!(a.sa_flags & SA_RESTORER)) { ++ a.sa_flags |= SA_RESTORER; ++ a.sa_restorer = (a.sa_flags & SA_SIGINFO) ++ ? LSS_NAME(restore_rt)() : LSS_NAME(restore)(); ++ } ++ #endif ++ } ++ rc = LSS_NAME(rt_sigaction)(signum, act ? &a : act, oldact, ++ (KERNEL_NSIG+7)/8); ++ if (rc < 0 && LSS_ERRNO == ENOSYS) { ++ struct kernel_old_sigaction oa, ooa, *ptr_a = &oa, *ptr_oa = &ooa; ++ if (!act) { ++ ptr_a = NULL; ++ } else { ++ oa.sa_handler_ = act->sa_handler_; ++ memcpy(&oa.sa_mask, &act->sa_mask, sizeof(oa.sa_mask)); ++ #ifndef __mips__ ++ oa.sa_restorer = act->sa_restorer; ++ #endif ++ oa.sa_flags = act->sa_flags; ++ } ++ if (!oldact) { ++ ptr_oa = NULL; ++ } ++ LSS_ERRNO = old_errno; ++ rc = LSS_NAME(_sigaction)(signum, ptr_a, ptr_oa); ++ if (rc == 0 && oldact) { ++ if (act) { ++ memcpy(oldact, act, sizeof(*act)); ++ } else { ++ memset(oldact, 0, sizeof(*oldact)); ++ } ++ oldact->sa_handler_ = ptr_oa->sa_handler_; ++ oldact->sa_flags = ptr_oa->sa_flags; ++ memcpy(&oldact->sa_mask, &ptr_oa->sa_mask, sizeof(ptr_oa->sa_mask)); ++ #ifndef __mips__ ++ oldact->sa_restorer = ptr_oa->sa_restorer; ++ #endif ++ } ++ } ++ return rc; ++ } ++ ++ LSS_INLINE int LSS_NAME(sigpending)(struct kernel_sigset_t *set) { ++ int old_errno = LSS_ERRNO; ++ int rc = LSS_NAME(rt_sigpending)(set, (KERNEL_NSIG+7)/8); ++ if (rc < 0 && LSS_ERRNO == ENOSYS) { ++ LSS_ERRNO = old_errno; ++ LSS_NAME(sigemptyset)(set); ++ rc = LSS_NAME(_sigpending)(&set->sig[0]); ++ } ++ return rc; ++ } ++ ++ LSS_INLINE int LSS_NAME(sigsuspend)(const struct kernel_sigset_t *set) { ++ int olderrno = LSS_ERRNO; ++ int rc = LSS_NAME(rt_sigsuspend)(set, (KERNEL_NSIG+7)/8); ++ if (rc < 0 && LSS_ERRNO == ENOSYS) { ++ LSS_ERRNO = olderrno; ++ rc = LSS_NAME(_sigsuspend)( ++ #ifndef __PPC__ ++ set, 0, ++ #endif ++ set->sig[0]); ++ } ++ return rc; ++ } ++ #endif ++ #if defined(__i386__) || \ ++ defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || \ ++ (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || \ ++ defined(__PPC__) || \ ++ (defined(__s390__) && !defined(__s390x__)) ++ /* On these architectures, implement mmap() with mmap2(). */ ++ LSS_INLINE void* LSS_NAME(mmap)(void *s, size_t l, int p, int f, int d, ++ int64_t o) { ++ if (o % 4096) { ++ LSS_ERRNO = EINVAL; ++ return (void *) -1; ++ } ++ return LSS_NAME(_mmap2)(s, l, p, f, d, (o / 4096)); ++ } ++ #elif defined(__s390x__) ++ /* On s390x, mmap() arguments are passed in memory. */ ++ LSS_INLINE void* LSS_NAME(mmap)(void *s, size_t l, int p, int f, int d, ++ int64_t o) { ++ unsigned long buf[6] = { (unsigned long) s, (unsigned long) l, ++ (unsigned long) p, (unsigned long) f, ++ (unsigned long) d, (unsigned long) o }; ++ LSS_REG(2, buf); ++ LSS_BODY(void*, mmap, "0"(__r2)); ++ } ++ #elif defined(__x86_64__) ++ /* Need to make sure __off64_t isn't truncated to 32-bits under x32. */ ++ LSS_INLINE void* LSS_NAME(mmap)(void *s, size_t l, int p, int f, int d, ++ int64_t o) { ++ LSS_BODY(6, void*, mmap, LSS_SYSCALL_ARG(s), LSS_SYSCALL_ARG(l), ++ LSS_SYSCALL_ARG(p), LSS_SYSCALL_ARG(f), ++ LSS_SYSCALL_ARG(d), (uint64_t)(o)); ++ } ++ #else ++ /* Remaining 64-bit architectures. */ ++ LSS_INLINE _syscall6(void*, mmap, void*, addr, size_t, length, int, prot, ++ int, flags, int, fd, int64_t, offset) ++ #endif ++ #if defined(__PPC__) ++ #undef LSS_SC_LOADARGS_0 ++ #define LSS_SC_LOADARGS_0(dummy...) ++ #undef LSS_SC_LOADARGS_1 ++ #define LSS_SC_LOADARGS_1(arg1) \ ++ __sc_4 = (unsigned long) (arg1) ++ #undef LSS_SC_LOADARGS_2 ++ #define LSS_SC_LOADARGS_2(arg1, arg2) \ ++ LSS_SC_LOADARGS_1(arg1); \ ++ __sc_5 = (unsigned long) (arg2) ++ #undef LSS_SC_LOADARGS_3 ++ #define LSS_SC_LOADARGS_3(arg1, arg2, arg3) \ ++ LSS_SC_LOADARGS_2(arg1, arg2); \ ++ __sc_6 = (unsigned long) (arg3) ++ #undef LSS_SC_LOADARGS_4 ++ #define LSS_SC_LOADARGS_4(arg1, arg2, arg3, arg4) \ ++ LSS_SC_LOADARGS_3(arg1, arg2, arg3); \ ++ __sc_7 = (unsigned long) (arg4) ++ #undef LSS_SC_LOADARGS_5 ++ #define LSS_SC_LOADARGS_5(arg1, arg2, arg3, arg4, arg5) \ ++ LSS_SC_LOADARGS_4(arg1, arg2, arg3, arg4); \ ++ __sc_8 = (unsigned long) (arg5) ++ #undef LSS_SC_BODY ++ #define LSS_SC_BODY(nr, type, opt, args...) \ ++ long __sc_ret, __sc_err; \ ++ { \ ++ register unsigned long __sc_0 __asm__ ("r0") = __NR_socketcall; \ ++ register unsigned long __sc_3 __asm__ ("r3") = opt; \ ++ register unsigned long __sc_4 __asm__ ("r4"); \ ++ register unsigned long __sc_5 __asm__ ("r5"); \ ++ register unsigned long __sc_6 __asm__ ("r6"); \ ++ register unsigned long __sc_7 __asm__ ("r7"); \ ++ register unsigned long __sc_8 __asm__ ("r8"); \ ++ LSS_SC_LOADARGS_##nr(args); \ ++ __asm__ __volatile__ \ ++ ("stwu 1, -48(1)\n\t" \ ++ "stw 4, 20(1)\n\t" \ ++ "stw 5, 24(1)\n\t" \ ++ "stw 6, 28(1)\n\t" \ ++ "stw 7, 32(1)\n\t" \ ++ "stw 8, 36(1)\n\t" \ ++ "addi 4, 1, 20\n\t" \ ++ "sc\n\t" \ ++ "mfcr %0" \ ++ : "=&r" (__sc_0), \ ++ "=&r" (__sc_3), "=&r" (__sc_4), \ ++ "=&r" (__sc_5), "=&r" (__sc_6), \ ++ "=&r" (__sc_7), "=&r" (__sc_8) \ ++ : LSS_ASMINPUT_##nr \ ++ : "cr0", "ctr", "memory"); \ ++ __sc_ret = __sc_3; \ ++ __sc_err = __sc_0; \ ++ } \ ++ LSS_RETURN(type, __sc_ret, __sc_err) ++ ++ LSS_INLINE ssize_t LSS_NAME(recvmsg)(int s,struct kernel_msghdr *msg, ++ int flags){ ++ LSS_SC_BODY(3, ssize_t, 17, s, msg, flags); ++ } ++ ++ LSS_INLINE ssize_t LSS_NAME(sendmsg)(int s, ++ const struct kernel_msghdr *msg, ++ int flags) { ++ LSS_SC_BODY(3, ssize_t, 16, s, msg, flags); ++ } ++ ++ // TODO(csilvers): why is this ifdef'ed out? ++#if 0 ++ LSS_INLINE ssize_t LSS_NAME(sendto)(int s, const void *buf, size_t len, ++ int flags, ++ const struct kernel_sockaddr *to, ++ unsigned int tolen) { ++ LSS_BODY(6, ssize_t, 11, s, buf, len, flags, to, tolen); ++ } ++#endif ++ ++ LSS_INLINE int LSS_NAME(shutdown)(int s, int how) { ++ LSS_SC_BODY(2, int, 13, s, how); ++ } ++ ++ LSS_INLINE int LSS_NAME(socket)(int domain, int type, int protocol) { ++ LSS_SC_BODY(3, int, 1, domain, type, protocol); ++ } ++ ++ LSS_INLINE int LSS_NAME(socketpair)(int d, int type, int protocol, ++ int sv[2]) { ++ LSS_SC_BODY(4, int, 8, d, type, protocol, sv); ++ } ++ #endif ++ #if defined(__NR_recvmsg) ++ LSS_INLINE _syscall3(ssize_t, recvmsg, int, s, struct kernel_msghdr*, msg, ++ int, flags) ++ #endif ++ #if defined(__NR_sendmsg) ++ LSS_INLINE _syscall3(ssize_t, sendmsg, int, s, const struct kernel_msghdr*, ++ msg, int, flags) ++ #endif ++ #if defined(__NR_sendto) ++ LSS_INLINE _syscall6(ssize_t, sendto, int, s, const void*, buf, size_t,len, ++ int, flags, const struct kernel_sockaddr*, to, ++ unsigned int, tolen) ++ #endif ++ #if defined(__NR_shutdown) ++ LSS_INLINE _syscall2(int, shutdown, int, s, int, how) ++ #endif ++ #if defined(__NR_socket) ++ LSS_INLINE _syscall3(int, socket, int, domain, int, type, int, protocol) ++ #endif ++ #if defined(__NR_socketpair) ++ LSS_INLINE _syscall4(int, socketpair, int, d, int, type, int, protocol, ++ int*, sv) ++ #endif ++ ++ #if defined(__NR_socketcall) ++ LSS_INLINE _syscall2(int, _socketcall, int, c, ++ va_list, a) ++ LSS_INLINE int LSS_NAME(socketcall)(int op, ...) { ++ int rc; ++ va_list ap; ++ va_start(ap, op); ++ rc = LSS_NAME(_socketcall)(op, ap); ++ va_end(ap); ++ return rc; ++ } ++ ++ # if !defined(__NR_recvmsg) ++ LSS_INLINE ssize_t LSS_NAME(recvmsg)(int s,struct kernel_msghdr *msg, ++ int flags){ ++ return (ssize_t)LSS_NAME(socketcall)(17, s, msg, flags); ++ } ++ # endif ++ # if !defined(__NR_sendmsg) ++ LSS_INLINE ssize_t LSS_NAME(sendmsg)(int s, ++ const struct kernel_msghdr *msg, ++ int flags) { ++ return (ssize_t)LSS_NAME(socketcall)(16, s, msg, flags); ++ } ++ # endif ++ # if !defined(__NR_sendto) ++ LSS_INLINE ssize_t LSS_NAME(sendto)(int s, const void *buf, size_t len, ++ int flags, ++ const struct kernel_sockaddr *to, ++ unsigned int tolen) { ++ return (ssize_t)LSS_NAME(socketcall)(11, s, buf, len, flags, to, tolen); ++ } ++ # endif ++ # if !defined(__NR_shutdown) ++ LSS_INLINE int LSS_NAME(shutdown)(int s, int how) { ++ return LSS_NAME(socketcall)(13, s, how); ++ } ++ # endif ++ # if !defined(__NR_socket) ++ LSS_INLINE int LSS_NAME(socket)(int domain, int type, int protocol) { ++ return LSS_NAME(socketcall)(1, domain, type, protocol); ++ } ++ # endif ++ # if !defined(__NR_socketpair) ++ LSS_INLINE int LSS_NAME(socketpair)(int d, int type, int protocol, ++ int sv[2]) { ++ return LSS_NAME(socketcall)(8, d, type, protocol, sv); ++ } ++ # endif ++ #endif ++ #if defined(__NR_fstatat64) ++ LSS_INLINE _syscall4(int, fstatat64, int, d, ++ const char *, p, ++ struct kernel_stat64 *, b, int, f) ++ #endif ++ #if defined(__NR_waitpid) ++ // waitpid is polyfilled below when not available. ++ LSS_INLINE _syscall3(pid_t, waitpid, pid_t, p, ++ int*, s, int, o) ++ #endif ++ #if defined(__mips__) ++ /* sys_pipe() on MIPS has non-standard calling conventions, as it returns ++ * both file handles through CPU registers. ++ */ ++ LSS_INLINE int LSS_NAME(pipe)(int *p) { ++ register unsigned long __v0 __asm__("$2") = __NR_pipe; ++ register unsigned long __v1 __asm__("$3"); ++ register unsigned long __r7 __asm__("$7"); ++ __asm__ __volatile__ ("syscall\n" ++ : "=r"(__v0), "=r"(__v1), "=r" (__r7) ++ : "0"(__v0) ++ : "$8", "$9", "$10", "$11", "$12", ++ "$13", "$14", "$15", "$24", "$25", "memory"); ++ if (__r7) { ++ unsigned long __errnovalue = __v0; ++ LSS_ERRNO = __errnovalue; ++ return -1; ++ } else { ++ p[0] = __v0; ++ p[1] = __v1; ++ return 0; ++ } ++ } ++ #elif defined(__NR_pipe) ++ // pipe is polyfilled below when not available. ++ LSS_INLINE _syscall1(int, pipe, int *, p) ++ #endif ++ #if defined(__NR_pipe2) ++ LSS_INLINE _syscall2(int, pipe2, int *, pipefd, int, flags) ++ #endif ++ /* TODO(csilvers): see if ppc can/should support this as well */ ++ #if defined(__i386__) || defined(__ARM_ARCH_3__) || \ ++ defined(__ARM_EABI__) || \ ++ (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI64) || \ ++ (defined(__s390__) && !defined(__s390x__)) ++ #define __NR__statfs64 __NR_statfs64 ++ #define __NR__fstatfs64 __NR_fstatfs64 ++ LSS_INLINE _syscall3(int, _statfs64, const char*, p, ++ size_t, s,struct kernel_statfs64*, b) ++ LSS_INLINE _syscall3(int, _fstatfs64, int, f, ++ size_t, s,struct kernel_statfs64*, b) ++ LSS_INLINE int LSS_NAME(statfs64)(const char *p, ++ struct kernel_statfs64 *b) { ++ return LSS_NAME(_statfs64)(p, sizeof(*b), b); ++ } ++ LSS_INLINE int LSS_NAME(fstatfs64)(int f,struct kernel_statfs64 *b) { ++ return LSS_NAME(_fstatfs64)(f, sizeof(*b), b); ++ } ++ #endif ++ ++ LSS_INLINE int LSS_NAME(execv)(const char *path, const char *const argv[]) { ++ extern char **environ; ++ return LSS_NAME(execve)(path, argv, (const char *const *)environ); ++ } ++ ++ LSS_INLINE pid_t LSS_NAME(gettid)(void) { ++ pid_t tid = LSS_NAME(_gettid)(); ++ if (tid != -1) { ++ return tid; ++ } ++ return LSS_NAME(getpid)(); ++ } ++ ++ LSS_INLINE void *LSS_NAME(mremap)(void *old_address, size_t old_size, ++ size_t new_size, int flags, ...) { ++ va_list ap; ++ void *new_address, *rc; ++ va_start(ap, flags); ++ new_address = va_arg(ap, void *); ++ rc = LSS_NAME(_mremap)(old_address, old_size, new_size, ++ (unsigned long)flags, new_address); ++ va_end(ap); ++ return rc; ++ } ++ ++ LSS_INLINE long LSS_NAME(ptrace_detach)(pid_t pid) { ++ /* PTRACE_DETACH can sometimes forget to wake up the tracee and it ++ * then sends job control signals to the real parent, rather than to ++ * the tracer. We reduce the risk of this happening by starting a ++ * whole new time slice, and then quickly sending a SIGCONT signal ++ * right after detaching from the tracee. ++ * ++ * We use tkill to ensure that we only issue a wakeup for the thread being ++ * detached. Large multi threaded apps can take a long time in the kernel ++ * processing SIGCONT. ++ */ ++ long rc; ++ int err; ++ LSS_NAME(sched_yield)(); ++ rc = LSS_NAME(ptrace)(PTRACE_DETACH, pid, (void *)0, (void *)0); ++ err = LSS_ERRNO; ++ LSS_NAME(tkill)(pid, SIGCONT); ++ /* Old systems don't have tkill */ ++ if (LSS_ERRNO == ENOSYS) ++ LSS_NAME(kill)(pid, SIGCONT); ++ LSS_ERRNO = err; ++ return rc; ++ } ++ ++ LSS_INLINE int LSS_NAME(raise)(int sig) { ++ return LSS_NAME(kill)(LSS_NAME(getpid)(), sig); ++ } ++ ++ LSS_INLINE int LSS_NAME(setpgrp)(void) { ++ return LSS_NAME(setpgid)(0, 0); ++ } ++ ++ #if defined(__x86_64__) ++ /* Need to make sure loff_t isn't truncated to 32-bits under x32. */ ++ LSS_INLINE ssize_t LSS_NAME(pread64)(int f, void *b, size_t c, loff_t o) { ++ LSS_BODY(4, ssize_t, pread64, LSS_SYSCALL_ARG(f), LSS_SYSCALL_ARG(b), ++ LSS_SYSCALL_ARG(c), (uint64_t)(o)); ++ } ++ ++ LSS_INLINE ssize_t LSS_NAME(pwrite64)(int f, const void *b, size_t c, ++ loff_t o) { ++ LSS_BODY(4, ssize_t, pwrite64, LSS_SYSCALL_ARG(f), LSS_SYSCALL_ARG(b), ++ LSS_SYSCALL_ARG(c), (uint64_t)(o)); ++ } ++ ++ LSS_INLINE int LSS_NAME(readahead)(int f, loff_t o, size_t c) { ++ LSS_BODY(3, int, readahead, LSS_SYSCALL_ARG(f), (uint64_t)(o), ++ LSS_SYSCALL_ARG(c)); ++ } ++ #elif defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI64 ++ LSS_INLINE _syscall4(ssize_t, pread64, int, f, ++ void *, b, size_t, c, ++ loff_t, o) ++ LSS_INLINE _syscall4(ssize_t, pwrite64, int, f, ++ const void *, b, size_t, c, ++ loff_t, o) ++ LSS_INLINE _syscall3(int, readahead, int, f, ++ loff_t, o, unsigned, c) ++ #else ++ #define __NR__pread64 __NR_pread64 ++ #define __NR__pwrite64 __NR_pwrite64 ++ #define __NR__readahead __NR_readahead ++ #if defined(__ARM_EABI__) || defined(__mips__) ++ /* On ARM and MIPS, a 64-bit parameter has to be in an even-odd register ++ * pair. Hence these calls ignore their fourth argument (r3) so that their ++ * fifth and sixth make such a pair (r4,r5). ++ */ ++ #define LSS_LLARG_PAD 0, ++ LSS_INLINE _syscall6(ssize_t, _pread64, int, f, ++ void *, b, size_t, c, ++ unsigned, skip, unsigned, o1, unsigned, o2) ++ LSS_INLINE _syscall6(ssize_t, _pwrite64, int, f, ++ const void *, b, size_t, c, ++ unsigned, skip, unsigned, o1, unsigned, o2) ++ LSS_INLINE _syscall5(int, _readahead, int, f, ++ unsigned, skip, ++ unsigned, o1, unsigned, o2, size_t, c) ++ #else ++ #define LSS_LLARG_PAD ++ LSS_INLINE _syscall5(ssize_t, _pread64, int, f, ++ void *, b, size_t, c, unsigned, o1, ++ unsigned, o2) ++ LSS_INLINE _syscall5(ssize_t, _pwrite64, int, f, ++ const void *, b, size_t, c, unsigned, o1, ++ unsigned, o2) ++ LSS_INLINE _syscall4(int, _readahead, int, f, ++ unsigned, o1, unsigned, o2, size_t, c) ++ #endif ++ /* We force 64bit-wide parameters onto the stack, then access each ++ * 32-bit component individually. This guarantees that we build the ++ * correct parameters independent of the native byte-order of the ++ * underlying architecture. ++ */ ++ LSS_INLINE ssize_t LSS_NAME(pread64)(int fd, void *buf, size_t count, ++ loff_t off) { ++ union { loff_t off; unsigned arg[2]; } o = { off }; ++ return LSS_NAME(_pread64)(fd, buf, count, ++ LSS_LLARG_PAD o.arg[0], o.arg[1]); ++ } ++ LSS_INLINE ssize_t LSS_NAME(pwrite64)(int fd, const void *buf, ++ size_t count, loff_t off) { ++ union { loff_t off; unsigned arg[2]; } o = { off }; ++ return LSS_NAME(_pwrite64)(fd, buf, count, ++ LSS_LLARG_PAD o.arg[0], o.arg[1]); ++ } ++ LSS_INLINE int LSS_NAME(readahead)(int fd, loff_t off, size_t count) { ++ union { loff_t off; unsigned arg[2]; } o = { off }; ++ return LSS_NAME(_readahead)(fd, LSS_LLARG_PAD o.arg[0], o.arg[1], count); ++ } ++ #endif ++#endif ++ ++/* ++ * Polyfills for deprecated syscalls. ++ */ ++ ++#if !defined(__NR_dup2) ++ LSS_INLINE int LSS_NAME(dup2)(int s, int d) { ++ return LSS_NAME(dup3)(s, d, 0); ++ } ++#endif ++ ++#if !defined(__NR_open) ++ LSS_INLINE int LSS_NAME(open)(const char *pathname, int flags, int mode) { ++ return LSS_NAME(openat)(AT_FDCWD, pathname, flags, mode); ++ } ++#endif ++ ++#if !defined(__NR_unlink) ++ LSS_INLINE int LSS_NAME(unlink)(const char *pathname) { ++ return LSS_NAME(unlinkat)(AT_FDCWD, pathname, 0); ++ } ++#endif ++ ++#if !defined(__NR_readlink) ++ LSS_INLINE int LSS_NAME(readlink)(const char *pathname, char *buffer, ++ size_t size) { ++ return LSS_NAME(readlinkat)(AT_FDCWD, pathname, buffer, size); ++ } ++#endif ++ ++#if !defined(__NR_pipe) ++ LSS_INLINE int LSS_NAME(pipe)(int *pipefd) { ++ return LSS_NAME(pipe2)(pipefd, 0); ++ } ++#endif ++ ++#if !defined(__NR_poll) ++ LSS_INLINE int LSS_NAME(poll)(struct kernel_pollfd *fds, unsigned int nfds, ++ int timeout) { ++ struct kernel_timespec timeout_ts; ++ struct kernel_timespec *timeout_ts_p = NULL; ++ ++ if (timeout >= 0) { ++ timeout_ts.tv_sec = timeout / 1000; ++ timeout_ts.tv_nsec = (timeout % 1000) * 1000000; ++ timeout_ts_p = &timeout_ts; ++ } ++ return LSS_NAME(ppoll)(fds, nfds, timeout_ts_p, NULL, 0); ++ } ++#endif ++ ++#if defined(__NR_statx) ++ /* copy the contents of kernel_statx to the kernel_stat structure. */ ++ LSS_INLINE void LSS_NAME(cp_stat_statx)(struct kernel_stat *to, ++ struct kernel_statx *from) { ++ memset(to, 0, sizeof(struct kernel_stat)); ++ to->st_dev = (kernel_dev_t)((from->stx_dev_minor & 0xff) | ++ ((from->stx_dev_major & 0xfff) << 8) | ++ ((from->stx_dev_minor & ~0xffu) << 12)); ++ to->st_rdev = (kernel_dev_t)((from->stx_rdev_minor & 0xff) | ++ ((from->stx_rdev_major & 0xfff) << 8) | ++ ((from->stx_rdev_minor & ~0xffu) << 12)); ++ to->st_ino = (kernel_ino_t)from->stx_ino; ++ to->st_mode = (kernel_mode_t)from->stx_mode; ++ to->st_nlink = (kernel_nlink_t)from->stx_nlink; ++ to->st_uid = (kernel_uid_t)from->stx_uid; ++ to->st_gid = (kernel_gid_t)from->stx_gid; ++ to->st_atime_ = (kernel_time_t)(from->stx_atime.tv_sec); ++ to->st_atime_nsec_ = from->stx_atime.tv_nsec; ++ to->st_mtime_ = (kernel_time_t)(from->stx_mtime.tv_sec); ++ to->st_mtime_nsec_ = from->stx_mtime.tv_nsec; ++ to->st_ctime_ = (kernel_time_t)(from->stx_ctime.tv_sec); ++ to->st_ctime_nsec_ = from->stx_ctime.tv_nsec; ++ to->st_size = (kernel_off_t)(from->stx_size); ++ to->st_blocks = (kernel_blkcnt_t)(from->stx_blocks); ++ to->st_blksize = (kernel_blksize_t)from->stx_blksize; ++ } ++#endif ++ ++#if !defined(__NR_fstat) ++ LSS_INLINE int LSS_NAME(fstat)(int fd, ++ struct kernel_stat *buf) { ++ #if defined(__NR_newfstatat) ++ return LSS_NAME(newfstatat)(fd, "", buf, AT_EMPTY_PATH); ++ #elif defined(__NR_statx) ++ struct kernel_statx stx; ++ int flags = AT_NO_AUTOMOUNT | AT_EMPTY_PATH; ++ int mask = STATX_BASIC_STATS; ++ int res = LSS_NAME(statx)(fd, "", flags, mask, &stx); ++ LSS_NAME(cp_stat_statx)(buf, &stx); ++ return res; ++ #endif ++ } ++#endif ++ ++#if !defined(__NR_stat) ++ LSS_INLINE int LSS_NAME(stat)(const char *pathname, ++ struct kernel_stat *buf) { ++ #if defined(__NR_newfstatat) ++ return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, 0); ++ #elif defined(__NR_statx) ++ struct kernel_statx stx; ++ int flags = AT_NO_AUTOMOUNT | AT_STATX_SYNC_AS_STAT; ++ int mask = STATX_BASIC_STATS; ++ int res = LSS_NAME(statx)(AT_FDCWD, pathname, flags, mask, &stx); ++ LSS_NAME(cp_stat_statx)(buf, &stx); ++ return res; ++ #endif ++ } ++#endif ++ ++#if !defined(__NR_lstat) ++ LSS_INLINE int LSS_NAME(lstat)(const char *pathname, ++ struct kernel_stat *buf) { ++ #if defined(__NR_newfstatat) ++ return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, AT_SYMLINK_NOFOLLOW); ++ #elif defined(__NR_statx) ++ struct kernel_statx stx; ++ int flags = AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW; ++ int mask = STATX_BASIC_STATS; ++ int res = LSS_NAME(statx)(AT_FDCWD, pathname, flags, mask, &stx); ++ LSS_NAME(cp_stat_statx)(buf, &stx); ++ return res; ++ #endif ++ } ++#endif ++ ++#if !defined(__NR_waitpid) ++ LSS_INLINE pid_t LSS_NAME(waitpid)(pid_t pid, int *status, int options) { ++ return LSS_NAME(wait4)(pid, status, options, 0); ++ } ++#endif ++ ++#if !defined(__NR_fork) ++// TODO: define this in an arch-independant way instead of inlining the clone ++// syscall body. ++ ++# if defined(__aarch64__) || defined(__riscv) || defined(__loongarch_lp64) ++ LSS_INLINE pid_t LSS_NAME(fork)(void) { ++ // No fork syscall on aarch64 - implement by means of the clone syscall. ++ // Note that this does not reset glibc's cached view of the PID/TID, so ++ // some glibc interfaces might go wrong in the forked subprocess. ++ int flags = SIGCHLD; ++ void *child_stack = NULL; ++ void *parent_tidptr = NULL; ++ void *newtls = NULL; ++ void *child_tidptr = NULL; ++ ++ LSS_REG(0, flags); ++ LSS_REG(1, child_stack); ++ LSS_REG(2, parent_tidptr); ++ LSS_REG(3, newtls); ++ LSS_REG(4, child_tidptr); ++ LSS_BODY(pid_t, clone, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), ++ "r"(__r4)); ++ } ++# elif defined(__x86_64__) ++ LSS_INLINE pid_t LSS_NAME(fork)(void) { ++ // Android disallows the fork syscall on x86_64 - implement by means of the ++ // clone syscall as above for aarch64. ++ int flags = SIGCHLD; ++ void *child_stack = NULL; ++ void *parent_tidptr = NULL; ++ void *newtls = NULL; ++ void *child_tidptr = NULL; ++ ++ LSS_BODY(5, pid_t, clone, LSS_SYSCALL_ARG(flags), ++ LSS_SYSCALL_ARG(child_stack), LSS_SYSCALL_ARG(parent_tidptr), ++ LSS_SYSCALL_ARG(newtls), LSS_SYSCALL_ARG(child_tidptr)); ++ } ++# else ++# error missing fork polyfill for this architecture ++# endif ++#endif ++ ++/* These restore the original values of these macros saved by the ++ * corresponding #pragma push_macro near the top of this file. */ ++#pragma pop_macro("stat64") ++#pragma pop_macro("fstat64") ++#pragma pop_macro("lstat64") ++#pragma pop_macro("pread64") ++#pragma pop_macro("pwrite64") ++#pragma pop_macro("getdents64") ++ ++#if defined(__cplusplus) && !defined(SYS_CPLUSPLUS) ++} ++#endif ++ ++#endif ++#endif +\ No newline at end of file diff --git a/test/AMBuilder b/test/AMBuilder deleted file mode 100644 index 4147c6d..0000000 --- a/test/AMBuilder +++ /dev/null @@ -1,89 +0,0 @@ -# vim: set ts=2 sw=2 tw=99 noet ft=python: -import os -import ambuild.osutil as osutil -from ambuild.command import SymlinkCommand -from ambuild.command import ShellCommand -from ambuild.command import DirectCommand - -def BuildEverything(): - if AMBuild.target['platform'] not in ['linux', 'windows']: - return - - compiler = SM.DefaultCompiler() - - if AMBuild.target['platform'] in ['linux']: - compiler['POSTLINKFLAGS'].append('-lm') - compiler['POSTLINKFLAGS'].append('-lstdc++') - compiler['POSTLINKFLAGS'].append('-pthread') - - compiler['CDEFINES'].append('HAVE_CONFIG_H') - compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'breakpad', 'build', 'src')) - elif compiler.cc.name == 'msvc': - compiler['POSTLINKFLAGS'].remove('/SUBSYSTEM:WINDOWS') - compiler['POSTLINKFLAGS'].append('/SUBSYSTEM:CONSOLE') - - compiler['CXXINCLUDES'].append(os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src')) - - name = 'test-crash-dump-generation' - extension = AMBuild.AddJob(name) - binary = Cpp.ExecutableBuilder(name, AMBuild, extension, compiler) - - binary.AddSourceFiles('test', [ - 'test.cpp', - ]); - - if AMBuild.target['platform'] in ['linux']: - binary.AddSourceFiles(os.path.join('breakpad', 'src', 'src', 'common'), [ - 'dwarf_cfi_to_module.cc', - 'dwarf_cu_to_module.cc', - 'dwarf_line_to_module.cc', - 'dwarf_range_list_handler.cc', - 'language.cc', - 'module.cc', - 'path_helper.cc', - 'stabs_reader.cc', - 'stabs_to_module.cc', - 'dwarf/bytereader.cc', - 'dwarf/dwarf2diehandler.cc', - 'dwarf/dwarf2reader.cc', - 'dwarf/elf_reader.cc', - 'linux/crc32.cc', - 'linux/dump_symbols.cc', - 'linux/elf_symbols_to_module.cc', - ]) - - if AMBuild.target['platform'] in ['linux']: - libs = [ - ('libbreakpad_client.a', os.path.join('breakpad', 'build', 'src', 'client', 'linux', 'libbreakpad_client.a')), - ('libbreakpad.a', os.path.join('breakpad', 'build', 'src', 'libbreakpad.a')), - ('libdisasm.a', os.path.join('breakpad', 'build', 'src', 'third_party', 'libdisasm', 'libdisasm.a')), - ] - - for lib, target in libs: - link = os.path.join(AMBuild.outputFolder, extension.workFolder, lib) - target = os.path.join(AMBuild.sourceFolder, target) - try: - os.lstat(link) - except: - extension.AddCommand(SymlinkCommand(link, target)) - binary.AddObjectFiles([lib]) - - elif AMBuild.target['platform'] in ['windows']: - libs = [ - os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src', 'client', 'windows', 'handler', 'Release', 'lib', 'common.lib'), - os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src', 'client', 'windows', 'handler', 'Release', 'lib', 'exception_handler.lib'), - os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src', 'client', 'windows', 'crash_generation', 'Release', 'lib', 'crash_generation_client.lib'), - os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src', 'third_party', 'libdisasm', 'Release', 'lib', 'libdisasm.lib'), - os.path.join(AMBuild.sourceFolder, 'breakpad', 'src', 'src', 'processor', 'Release', 'lib', 'processor.lib'), - ] - - for path in libs: - if os.path.isfile(path): - binary.RelinkIfNewer(path) - binary['POSTLINKFLAGS'].extend([path]) - - SM.ExtractDebugInfo(extension, binary) - - binary.SendToJob() - -BuildEverything() diff --git a/test/test.cpp b/test/test.cpp deleted file mode 100644 index 1a3ef1e..0000000 --- a/test/test.cpp +++ /dev/null @@ -1,326 +0,0 @@ -#if defined _LINUX -#include "client/linux/handler/exception_handler.h" -#include "common/linux/linux_libc_support.h" -#include "third_party/lss/linux_syscall_support.h" -#include "common/linux/dump_symbols.h" -#include "common/path_helper.h" - -#include -#include -#include -#include - -#define my_jmp_buf sigjmp_buf -#define my_setjmp(x) sigsetjmp(x, 0) -#define my_longjmp siglongjmp - -using google_breakpad::MinidumpDescriptor; -using google_breakpad::WriteSymbolFile; - -class StderrInhibitor -{ - FILE *saved_stderr = nullptr; - -public: - StderrInhibitor() { - saved_stderr = fdopen(dup(fileno(stderr)), "w"); - if (freopen(_PATH_DEVNULL, "w", stderr)) { - // If it fails, not a lot we can (or should) do. - // Add this brace section to silence gcc warnings. - } - } - - ~StderrInhibitor() { - fflush(stderr); - dup2(fileno(saved_stderr), fileno(stderr)); - fclose(saved_stderr); - } -}; - -#elif defined _WINDOWS -#define _STDINT // ~.~ -#include "client/windows/handler/exception_handler.h" - -#define my_jmp_buf jmp_buf -#define my_setjmp(x) setjmp(x) -#define my_longjmp longjmp - -#else -#error Bad platform. -#endif - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -using google_breakpad::ExceptionHandler; - -using google_breakpad::Minidump; -using google_breakpad::MinidumpProcessor; -using google_breakpad::ProcessState; -using google_breakpad::ProcessResult; -using google_breakpad::CallStack; -using google_breakpad::StackFrame; -using google_breakpad::PathnameStripper; -using google_breakpad::CodeModule; - -class ClogInhibitor -{ - std::streambuf *saved_clog = nullptr; - -public: - ClogInhibitor() { - saved_clog = std::clog.rdbuf(); - std::clog.rdbuf(nullptr); - } - - ~ClogInhibitor() { - std::clog.rdbuf(saved_clog); - } -}; - -my_jmp_buf envbuf; -char path[1024]; - -#if defined _LINUX -static bool dumpCallback(const MinidumpDescriptor &descriptor, void *context, bool succeeded) -{ - if (succeeded) { - sys_write(STDOUT_FILENO, "Wrote minidump to: ", 19); - } else { - sys_write(STDOUT_FILENO, "Failed to write minidump to: ", 29); - } - - sys_write(STDOUT_FILENO, descriptor.path(), my_strlen(descriptor.path())); - sys_write(STDOUT_FILENO, "\n", 1); - - my_strlcpy(path, descriptor.path(), sizeof(path)); - my_longjmp(envbuf, 1); - - return succeeded; -} -#elif defined _WINDOWS -static bool dumpCallback(const wchar_t *dump_path, const wchar_t *minidump_id, void *context, EXCEPTION_POINTERS *exinfo, MDRawAssertionInfo *assertion, bool succeeded) -{ - if (succeeded) { - printf("Wrote minidump to: %ls\\%ls.dmp\n", dump_path, minidump_id); - } else { - printf("Failed to write minidump to: %ls\\%ls.dmp\n", dump_path, minidump_id); - } - - // TODO: setjmp/longjmp doesn't play nicely with SEH on Windows, so we never get back. - // But the exception handler is called and writes the dump, so the user can just invoke us again. - - // snprintf(path, sizeof(path), "%ls\\%ls.dmp", dump_path, minidump_id); - // my_longjmp(envbuf, 1); - - return succeeded; -} -#endif - -int main(int argc, char *argv[]) -{ - bool shouldDumpSymbols = false; - if (argc > 1 && strcmp(argv[1], "-d") == 0) { - shouldDumpSymbols = true; - } - - bool generateCrash = false; - if (argc <= (shouldDumpSymbols ? 2 : 1)) { - generateCrash = true; - - if (my_setjmp(envbuf) == 0) { -#if defined _LINUX - MinidumpDescriptor descriptor("."); - ExceptionHandler *handler = new ExceptionHandler(descriptor, NULL, dumpCallback, NULL, true, -1); -#elif defined _WINDOWS - ExceptionHandler *handler = new ExceptionHandler(L".", NULL, dumpCallback, NULL, ExceptionHandler::HANDLER_ALL); -#endif - - volatile int *ptr = (volatile int *)(0xdeadbeef); - *ptr = 0; - - delete handler; - return 0; - } - - printf("Returned from signal handler, path: %s\n", path); - - argc = (shouldDumpSymbols ? 3 : 2); - } - - for (int i = (shouldDumpSymbols ? 2 : 1); i < argc; ++i) { - if (!generateCrash) { - strncpy(path, argv[i], sizeof(path)); - } - - ProcessState processState; - ProcessResult processResult; - MinidumpProcessor minidumpProcessor(nullptr, nullptr); - - { - ClogInhibitor clogInhibitor; - processResult = minidumpProcessor.Process(path, &processState); - } - - if (processResult != google_breakpad::PROCESS_OK) { - continue; - } - - std::string os_short = ""; - std::string cpu_arch = ""; - if (processState.system_info()) { - os_short = processState.system_info()->os_short; - if (os_short.empty()) { - os_short = processState.system_info()->os; - } - cpu_arch = processState.system_info()->cpu; - } - - int requestingThread = processState.requesting_thread(); - if (requestingThread == -1) { - requestingThread = 0; - } - - const CallStack *stack = processState.threads()->at(requestingThread); - if (!stack) { - continue; - } - - int frameCount = stack->frames()->size(); - if (frameCount > 1024) { - frameCount = 1024; - } - - std::ostringstream summaryStream; - summaryStream << 2 << "|" << processState.time_date_stamp() << "|" << os_short << "|" << cpu_arch << "|" << processState.crashed() << "|" << processState.crash_reason() << "|" << std::hex << processState.crash_address() << std::dec << "|" << requestingThread; - - std::map moduleMap; - - unsigned int moduleCount = processState.modules() ? processState.modules()->module_count() : 0; - for (unsigned int moduleIndex = 0; moduleIndex < moduleCount; ++moduleIndex) { - auto module = processState.modules()->GetModuleAtIndex(moduleIndex); - moduleMap[module] = moduleIndex; - - auto debugFile = PathnameStripper::File(module->debug_file()); - auto debugIdentifier = module->debug_identifier(); - - summaryStream << "|M|" << debugFile << "|" << debugIdentifier; - } - - for (int frameIndex = 0; frameIndex < frameCount; ++frameIndex) { - const StackFrame *frame = stack->frames()->at(frameIndex); - - int moduleIndex = -1; - auto moduleOffset = frame->ReturnAddress(); - if (frame->module) { - moduleIndex = moduleMap[frame->module]; - moduleOffset -= frame->module->base_address(); - } - - summaryStream << "|F|" << moduleIndex << "|" << std::hex << moduleOffset << std::dec; - } - - auto summaryLine = summaryStream.str(); - printf("%s\n", summaryLine.c_str()); - -#if defined _LINUX - for (unsigned int moduleIndex = 0; shouldDumpSymbols && moduleIndex < moduleCount; ++moduleIndex) { - auto module = processState.modules()->GetModuleAtIndex(moduleIndex); - - auto debugFile = module->debug_file(); - std::string vdsoOutputPath = ""; - - if (debugFile == "linux-gate.so") { - FILE *auxvFile = fopen("/proc/self/auxv", "rb"); - if (auxvFile) { - auto workingDir = getcwd(nullptr, 0); - vdsoOutputPath = workingDir + std::string("/linux-gate.so"); - free(workingDir); - - while (!feof(auxvFile)) { - int auxvEntryId = 0; - fread(&auxvEntryId, sizeof(auxvEntryId), 1, auxvFile); - long auxvEntryValue = 0; - fread(&auxvEntryValue, sizeof(auxvEntryValue), 1, auxvFile); - - if (auxvEntryId == 0) break; - if (auxvEntryId != 33) continue; // AT_SYSINFO_EHDR - - Elf32_Ehdr *vdsoHdr = (Elf32_Ehdr *)auxvEntryValue; - auto vdsoSize = vdsoHdr->e_shoff + (vdsoHdr->e_shentsize * vdsoHdr->e_shnum); - void *vdsoBuffer = malloc(vdsoSize); - memcpy(vdsoBuffer, vdsoHdr, vdsoSize); - - FILE *vdsoFile = fopen(vdsoOutputPath.c_str(), "wb"); - if (vdsoFile) { - fwrite(vdsoBuffer, 1, vdsoSize, vdsoFile); - fclose(vdsoFile); - debugFile = vdsoOutputPath; - } - - free(vdsoBuffer); - break; - } - - fclose(auxvFile); - } - } - - if (debugFile[0] != '/') { - continue; - } - - // printf("%s\n", debugFile.c_str()); - - auto debugFileDir = google_breakpad::DirName(debugFile); - std::vector debug_dirs{ - debugFileDir, - debugFileDir + "/.debug", - "/usr/lib/debug" + debugFileDir, - }; - - std::ostringstream outputStream; - google_breakpad::DumpOptions options(ALL_SYMBOL_DATA, true); - - { - StderrInhibitor stdrrInhibitor; - - if (!WriteSymbolFile(debugFile, debug_dirs, options, outputStream)) { - outputStream.str(""); - outputStream.clear(); - - // Try again without debug dirs. - if (!WriteSymbolFile(debugFile, {}, options, outputStream)) { - // TODO: Something. - continue; - } - } - } - - // WriteSymbolFileHeaderOnly would do this for us, but this is just for testing. - auto output = outputStream.str(); - output = output.substr(0, output.find("\n")); - printf("%s\n", output.c_str()); - - if (debugFile == vdsoOutputPath) { - unlink(vdsoOutputPath.c_str()); - } - } -#endif - } - - if (generateCrash) { - unlink(path); - } - - return 0; -} diff --git a/third_party/AMBuilder b/third_party/AMBuilder new file mode 100644 index 0000000..a7b3e5f --- /dev/null +++ b/third_party/AMBuilder @@ -0,0 +1,173 @@ +# vim: set ts=2 sw=2 tw=99 noet ft=python: +import os, sys + +def AddSourceFilesFromDir(path, files): + list = [] + for file in files: + list.append(os.path.join(path, file)) + return list + +builder.SetBuildFolder('./third_party') + +libz = builder.StaticLibraryProject('libz') +libz.sources = AddSourceFilesFromDir(os.path.join(builder.currentSourcePath, 'zlib'),[ + 'adler32.c', + 'compress.c', + 'crc32.c', + 'deflate.c', + 'gzclose.c', + 'gzlib.c', + 'gzread.c', + 'gzwrite.c', + 'infback.c', + 'inffast.c', + 'inflate.c', + 'inftrees.c', + 'trees.c', + 'uncompr.c', + 'zutil.c' +]) + +for cxx in Accelerator.targets: + if cxx.target.platform == 'linux': + binary = Accelerator.ConfigureLibrary(libz, cxx, builder) + binary.compiler.cflags += ['-Wno-implicit-function-declaration'] + +Accelerator.libz = builder.Add(libz) + +libbreakpad_client = builder.StaticLibraryProject('libbreakpad_client') +libbreakpad_client.sources = AddSourceFilesFromDir(os.path.join(builder.currentSourcePath, 'breakpad', 'src'),[ + 'common/convert_UTF.cc', + 'common/string_conversion.cc', +]) + +libbreakpad_client_linux = AddSourceFilesFromDir(os.path.join(builder.currentSourcePath, 'breakpad', 'src'),[ + 'client/minidump_file_writer.cc', + 'client/linux/crash_generation/crash_generation_client.cc', + 'client/linux/crash_generation/crash_generation_server.cc', + 'client/linux/dump_writer_common/thread_info.cc', + 'client/linux/dump_writer_common/ucontext_reader.cc', + 'client/linux/handler/exception_handler.cc', + 'client/linux/handler/minidump_descriptor.cc', + 'client/linux/log/log.cc', + 'client/linux/microdump_writer/microdump_writer.cc', + 'client/linux/minidump_writer/linux_core_dumper.cc', + 'client/linux/minidump_writer/linux_dumper.cc', + 'client/linux/minidump_writer/linux_ptrace_dumper.cc', + 'client/linux/minidump_writer/minidump_writer.cc', + 'client/linux/minidump_writer/pe_file.cc', + 'common/linux/elf_core_dump.cc', + 'common/linux/elfutils.cc', + 'common/linux/file_id.cc', + 'common/linux/guid_creator.cc', + 'common/linux/linux_libc_support.cc', + 'common/linux/memory_mapped_file.cc', + 'common/linux/safe_readlink.cc' +]) + +libbreakpad_client_windows = AddSourceFilesFromDir(os.path.join(builder.currentSourcePath, 'breakpad', 'src'),[ + 'client/windows/crash_generation/client_info.cc', + 'client/windows/crash_generation/crash_generation_client.cc', + 'client/windows/crash_generation/crash_generation_server.cc', + 'client/windows/crash_generation/minidump_generator.cc', + 'client/windows/handler/exception_handler.cc', + 'common/windows/guid_string.cc' +]) + +libbreakpad = builder.StaticLibraryProject('libbreakpad') +libbreakpad.sources = AddSourceFilesFromDir(os.path.join(builder.currentSourcePath, 'breakpad', 'src'),[ + 'processor/basic_code_modules.cc', + 'processor/basic_source_line_resolver.cc', + 'processor/call_stack.cc', + 'processor/cfi_frame_info.cc', + 'processor/convert_old_arm64_context.cc', + 'processor/disassembler_x86.cc', + 'processor/dump_context.cc', + 'processor/dump_object.cc', + 'processor/exploitability.cc', + 'processor/exploitability_linux.cc', + 'processor/exploitability_win.cc', + 'processor/fast_source_line_resolver.cc', + 'processor/logging.cc', + 'processor/microdump.cc', + 'processor/microdump_processor.cc', + 'processor/minidump.cc', + 'processor/minidump_processor.cc', + 'processor/module_comparer.cc', + 'processor/module_serializer.cc', + 'processor/pathname_stripper.cc', + 'processor/process_state.cc', + 'processor/proc_maps_linux.cc', + 'processor/simple_symbol_supplier.cc', + 'processor/source_line_resolver_base.cc', + 'processor/stack_frame_cpu.cc', + 'processor/stack_frame_symbolizer.cc', + 'processor/stackwalk_common.cc', + 'processor/stackwalker.cc', + 'processor/stackwalker_amd64.cc', + 'processor/stackwalker_arm.cc', + 'processor/stackwalker_arm64.cc', + 'processor/stackwalker_address_list.cc', + 'processor/stackwalker_mips.cc', + 'processor/stackwalker_ppc.cc', + 'processor/stackwalker_ppc64.cc', + 'processor/stackwalker_riscv.cc', + 'processor/stackwalker_riscv64.cc', + 'processor/stackwalker_sparc.cc', + 'processor/stackwalker_x86.cc', + 'processor/symbolic_constants_win.cc', + 'processor/tokenize.cc' +]) + +libbreakpad_linux = AddSourceFilesFromDir(os.path.join(builder.currentSourcePath, 'breakpad', 'src'),[ + 'common/linux/scoped_pipe.cc', + 'common/linux/scoped_tmpfile.cc', + 'processor/disassembler_objdump.cc' +]) + +libbreakpad_windows = [] + +libdisasm = builder.StaticLibraryProject('libdisasm') +libdisasm.sources = AddSourceFilesFromDir(os.path.join(builder.currentSourcePath, 'breakpad', 'src', 'third_party', 'libdisasm'),[ + 'ia32_implicit.c', + 'ia32_insn.c', + 'ia32_invariant.c', + 'ia32_modrm.c', + 'ia32_opcode_tables.c', + 'ia32_operand.c', + 'ia32_reg.c', + 'ia32_settings.c', + 'x86_disasm.c', + 'x86_format.c', + 'x86_imm.c', + 'x86_insn.c', + 'x86_misc.c', + 'x86_operand_list.c' +]) + +libraries = [libbreakpad_client, libbreakpad, libdisasm] +libraries_platform_src = [(libbreakpad_client_linux, libbreakpad_client_windows), (libbreakpad_linux, libbreakpad_windows), ([],[])] + +for cxx in Accelerator.targets: + for (library, (linux_src, windows_src)) in zip(libraries, libraries_platform_src): + binary = Accelerator.ConfigureLibrary(library, cxx, builder) + compiler = binary.compiler + # Wait for breakpad to be patched + compiler.sourcedeps += Accelerator.breakpad_patch + + if compiler.target.platform == 'linux': + # Link against our zlib if linux + Accelerator.link_libz(cxx, builder) + binary.sources += linux_src + if compiler.target.platform == 'windows': + binary.sources += windows_src + + compiler.cxxincludes += [ + os.path.join(builder.currentSourcePath, 'breakpad', 'src') + ] + + compiler.defines += ['UNICODE'] + +Accelerator.libbreakpad = builder.Add(libbreakpad) +Accelerator.libbreakpad_client = builder.Add(libbreakpad_client) +Accelerator.libdisasm = builder.Add(libdisasm) \ No newline at end of file diff --git a/third_party/Configure b/third_party/Configure new file mode 100644 index 0000000..139605d --- /dev/null +++ b/third_party/Configure @@ -0,0 +1,104 @@ +# vim: set ts=2 sw=2 tw=99 noet ft=python: +import os, sys + +builder.SetBuildFolder('third_party/config') +for compiler in Accelerator.targets: + output = """ +/* define if the compiler supports basic C++17 syntax */ +#define HAVE_CXX17 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + """ + if compiler.target.platform == "linux": + output += """ +/* Define to 1 if you have the header file. */ +#define HAVE_A_OUT_H 1 + +/* Define to 1 if you have the `getcontext' function. */ +#define HAVE_GETCONTEXT 1 + +/* Define to 1 if you have the `getrandom' function. */ +#define HAVE_GETRANDOM 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_MMAN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_RANDOM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the `memfd_create' function. */ +#define HAVE_MEMFD_CREATE 1 + """ + + if '-lrustc_demangle' in compiler.postlink: + output += """ +/* Define to 1 if you have the `rustc_demangle' library (-lrustc_demangle). */ +#define HAVE_LIBRUSTC_DEMANGLE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_RUSTC_DEMANGLE_H 1 + """ + + if '-pthread' in compiler.postlink: + output += """ +/* Define if you have POSIX threads libraries and header files. */ +#define HAVE_PTHREAD 1 + """ + + if '-lzstd' in compiler.postlink: + output += """ +/* Define to 1 if you have the `zstd' library (-lzstd). */ +#define HAVE_LIBZSTD 1 + """ + + output += """ +/* Name of package */ +#define PACKAGE "breakpad" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "google-breakpad-dev@googlegroups.com" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "breakpad" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "breakpad 0.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "breakpad" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.1" + +/* Version number of package */ +#define VERSION "0.1" +""" + Accelerator.breakpad_config[compiler.target.arch] = [builder.AddOutputFile(os.path.join(compiler.target.arch, 'config.h'), output.encode())] \ No newline at end of file diff --git a/third_party/Patch b/third_party/Patch new file mode 100644 index 0000000..f1df2f3 --- /dev/null +++ b/third_party/Patch @@ -0,0 +1,81 @@ +# vim: set ts=2 sw=2 tw=99 noet ft=python: +import os, sys +import re + +def Normalize(path): + return os.path.abspath(os.path.normpath(os.path.join(path))) + +def AddFilesFromDir(path, files): + list = [] + for file in files: + list.append(os.path.join(path, file)) + return list + +def AddCwdCommand(context, cwd, inputs, + argv, + outputs, + folder = -1, + dep_type = None, + weak_inputs = [], + shared_outputs = [], + env_data = None, + fake_output = None): + + base_argv = [ + sys.executable, + Normalize(os.path.join(context.currentSourcePath, 'cwd_cmd.py')), + cwd, + os.path.join(context.buildPath, 'third_party', fake_output) if fake_output else '_', + ] + if fake_output : + outputs += [fake_output] + return context.AddCommand(inputs=inputs, argv=base_argv + argv, outputs=outputs, folder=folder, dep_type=dep_type, weak_inputs=weak_inputs, shared_outputs=shared_outputs, env_data=env_data) + + +git_dir = Normalize(os.path.join(builder.currentSourcePath, 'breakpad')) +patches = AddFilesFromDir(os.path.join(builder.currentSourcePath, '..', 'patches'), [ + "0001-Ignore-invalid-modules-rather-than-bailing-on-the-en.patch", + "0002-Write-FUNC-records-instead-of-PUBLIC-for-ELF-symbols.patch", + "0003-Support-compilation-on-VS-2015.patch", + "0004-Fix-Linux-a-out-include.patch", + "0005-Add-LSS.patch" +]) + +# Reset the breakpad directory before applying patches +argv = [ + 'git', + 'clean', + '-fdx', + '&&', + 'git', + 'reset', + '--hard' +] + +git_reset = AddCwdCommand(builder, git_dir, + inputs=patches, # We want the reset to happen again if we modify the patch files + outputs=[], + fake_output='git_clean.txt', + argv=argv) + +# Apply each of the patch available to the breakpad repository +argv = [ + 'git', + 'apply', + '--reject' +] + +git_patches = [] +num = 0 +for patch in patches: + patch_argv = argv + [patch] + git_patches += AddCwdCommand(builder, git_dir, + inputs=patches, # Redo the command if the patches changed + outputs=[], + fake_output=str(num) + '_patch.txt', + argv=patch_argv, + weak_inputs=git_reset if num == 0 else [git_patches[-1]] + git_reset # We need to for the git reset to be performed + ) + num = num + 1 + +Accelerator.breakpad_patch = git_reset + git_patches \ No newline at end of file diff --git a/third_party/breakpad b/third_party/breakpad new file mode 160000 index 0000000..255dbbd --- /dev/null +++ b/third_party/breakpad @@ -0,0 +1 @@ +Subproject commit 255dbbd061a400e7a3f601e82a62e65058b39e5e diff --git a/third_party/cwd_cmd.py b/third_party/cwd_cmd.py new file mode 100644 index 0000000..0d361aa --- /dev/null +++ b/third_party/cwd_cmd.py @@ -0,0 +1,21 @@ +# vim: set ts=2 sw=2 tw=99 noet ft=python: +import subprocess, sys + +argv = sys.argv[3:] +cwd = sys.argv[1] +print('CMD: ' + ' '.join(argv)) +print('CWD: ' + cwd) +print('OUT: ' + sys.argv[2]) +open(sys.argv[2], 'a').close() + +args = { 'args': ' '.join(argv), + 'stdout': subprocess.PIPE, + 'stderr': subprocess.PIPE, + 'shell': True, + 'cwd': cwd } +p = subprocess.Popen(**args) +stdout, stderr = p.communicate() +print(stdout.decode("utf-8")) +if p.returncode != 0: + print(stderr.decode("utf-8")) +sys.exit(p.returncode) diff --git a/third_party/zlib b/third_party/zlib new file mode 160000 index 0000000..d476828 --- /dev/null +++ b/third_party/zlib @@ -0,0 +1 @@ +Subproject commit d476828316d05d54c6fd6a068b121b30c147b5cd