11cb0ef41Sopenharmony_ci#ifndef POSTJECT_API_H_
21cb0ef41Sopenharmony_ci#define POSTJECT_API_H_
31cb0ef41Sopenharmony_ci
41cb0ef41Sopenharmony_ci#include <stdbool.h>
51cb0ef41Sopenharmony_ci#include <stddef.h>
61cb0ef41Sopenharmony_ci#include <stdlib.h>
71cb0ef41Sopenharmony_ci#include <string.h>
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci#if defined(__APPLE__) && defined(__MACH__)
101cb0ef41Sopenharmony_ci#include <mach-o/dyld.h>
111cb0ef41Sopenharmony_ci#include <mach-o/getsect.h>
121cb0ef41Sopenharmony_ci#elif defined(__linux__)
131cb0ef41Sopenharmony_ci#include <elf.h>
141cb0ef41Sopenharmony_ci#include <link.h>
151cb0ef41Sopenharmony_ci#include <sys/param.h>
161cb0ef41Sopenharmony_ci#elif defined(_WIN32)
171cb0ef41Sopenharmony_ci#include <windows.h>
181cb0ef41Sopenharmony_ci#endif
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_ci#ifndef POSTJECT_SENTINEL_FUSE
211cb0ef41Sopenharmony_ci#define POSTJECT_SENTINEL_FUSE \
221cb0ef41Sopenharmony_ci  "POSTJECT_SENTINEL_fce680ab2cc467b6e072b8b5df1996b2"
231cb0ef41Sopenharmony_ci#endif
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_cistruct postject_options {
261cb0ef41Sopenharmony_ci  const char* elf_section_name;
271cb0ef41Sopenharmony_ci  const char* macho_framework_name;
281cb0ef41Sopenharmony_ci  const char* macho_section_name;
291cb0ef41Sopenharmony_ci  const char* macho_segment_name;
301cb0ef41Sopenharmony_ci  const char* pe_resource_name;
311cb0ef41Sopenharmony_ci};
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ciinline void postject_options_init(struct postject_options* options) {
341cb0ef41Sopenharmony_ci  options->elf_section_name = NULL;
351cb0ef41Sopenharmony_ci  options->macho_framework_name = NULL;
361cb0ef41Sopenharmony_ci  options->macho_section_name = NULL;
371cb0ef41Sopenharmony_ci  options->macho_segment_name = NULL;
381cb0ef41Sopenharmony_ci  options->pe_resource_name = NULL;
391cb0ef41Sopenharmony_ci}
401cb0ef41Sopenharmony_ci
411cb0ef41Sopenharmony_cistatic inline bool postject_has_resource() {
421cb0ef41Sopenharmony_ci  static const volatile char* sentinel = POSTJECT_SENTINEL_FUSE ":0";
431cb0ef41Sopenharmony_ci  return sentinel[sizeof(POSTJECT_SENTINEL_FUSE)] == '1';
441cb0ef41Sopenharmony_ci}
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci#if defined(__linux__)
471cb0ef41Sopenharmony_cistatic int postject__dl_iterate_phdr_callback(struct dl_phdr_info* info,
481cb0ef41Sopenharmony_ci                                              size_t size,
491cb0ef41Sopenharmony_ci                                              void* data) {
501cb0ef41Sopenharmony_ci  // Snag the dl_phdr_info struct for the main program, then stop iterating
511cb0ef41Sopenharmony_ci  *((struct dl_phdr_info*)data) = *info;
521cb0ef41Sopenharmony_ci  return 1;
531cb0ef41Sopenharmony_ci}
541cb0ef41Sopenharmony_ci#endif
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_cistatic const void* postject_find_resource(
571cb0ef41Sopenharmony_ci    const char* name,
581cb0ef41Sopenharmony_ci    size_t* size,
591cb0ef41Sopenharmony_ci    const struct postject_options* options) {
601cb0ef41Sopenharmony_ci  // Always zero out the size pointer to start
611cb0ef41Sopenharmony_ci  if (size != NULL) {
621cb0ef41Sopenharmony_ci    *size = 0;
631cb0ef41Sopenharmony_ci  }
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ci#if defined(__APPLE__) && defined(__MACH__)
661cb0ef41Sopenharmony_ci  char* section_name = NULL;
671cb0ef41Sopenharmony_ci  const char* segment_name = "__POSTJECT";
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ci  if (options != NULL && options->macho_segment_name != NULL) {
701cb0ef41Sopenharmony_ci    segment_name = options->macho_segment_name;
711cb0ef41Sopenharmony_ci  }
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci  if (options != NULL && options->macho_section_name != NULL) {
741cb0ef41Sopenharmony_ci    name = options->macho_section_name;
751cb0ef41Sopenharmony_ci  } else if (strncmp(name, "__", 2) != 0) {
761cb0ef41Sopenharmony_ci    // Automatically prepend __ to match naming convention
771cb0ef41Sopenharmony_ci    section_name = (char*)malloc(strlen(name) + 3);
781cb0ef41Sopenharmony_ci    if (section_name == NULL) {
791cb0ef41Sopenharmony_ci      return NULL;
801cb0ef41Sopenharmony_ci    }
811cb0ef41Sopenharmony_ci    strcpy(section_name, "__");
821cb0ef41Sopenharmony_ci    strcat(section_name, name);
831cb0ef41Sopenharmony_ci  }
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci  unsigned long section_size;
861cb0ef41Sopenharmony_ci  char* ptr = NULL;
871cb0ef41Sopenharmony_ci  if (options != NULL && options->macho_framework_name != NULL) {
881cb0ef41Sopenharmony_ci#ifdef __clang__
891cb0ef41Sopenharmony_ci#pragma clang diagnostic push
901cb0ef41Sopenharmony_ci#pragma clang diagnostic ignored "-Wdeprecated-declarations"
911cb0ef41Sopenharmony_ci#endif
921cb0ef41Sopenharmony_ci    ptr = getsectdatafromFramework(options->macho_framework_name, segment_name,
931cb0ef41Sopenharmony_ci                                   section_name != NULL ? section_name : name,
941cb0ef41Sopenharmony_ci                                   &section_size);
951cb0ef41Sopenharmony_ci  } else {
961cb0ef41Sopenharmony_ci    ptr = getsectdata(segment_name, section_name != NULL ? section_name : name,
971cb0ef41Sopenharmony_ci                      &section_size);
981cb0ef41Sopenharmony_ci#ifdef __clang__
991cb0ef41Sopenharmony_ci#pragma clang diagnostic pop
1001cb0ef41Sopenharmony_ci#endif
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci    if (ptr != NULL) {
1031cb0ef41Sopenharmony_ci      // Add the "virtual memory address slide" amount to ensure a valid pointer
1041cb0ef41Sopenharmony_ci      // in cases where the virtual memory address have been adjusted by the OS.
1051cb0ef41Sopenharmony_ci      //
1061cb0ef41Sopenharmony_ci      // NOTE - `getsectdataFromFramework` already handles this adjustment for
1071cb0ef41Sopenharmony_ci      //        us, which is why we only do it for `getsectdata`, see:
1081cb0ef41Sopenharmony_ci      //        https://web.archive.org/web/20220613234007/https://opensource.apple.com/source/cctools/cctools-590/libmacho/getsecbyname.c.auto.html
1091cb0ef41Sopenharmony_ci      ptr += _dyld_get_image_vmaddr_slide(0);
1101cb0ef41Sopenharmony_ci    }
1111cb0ef41Sopenharmony_ci  }
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ci  free(section_name);
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci  if (size != NULL) {
1161cb0ef41Sopenharmony_ci    *size = (size_t)section_size;
1171cb0ef41Sopenharmony_ci  }
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci  return ptr;
1201cb0ef41Sopenharmony_ci#elif defined(__linux__)
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci  if (options != NULL && options->elf_section_name != NULL) {
1231cb0ef41Sopenharmony_ci    name = options->elf_section_name;
1241cb0ef41Sopenharmony_ci  }
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci  struct dl_phdr_info main_program_info;
1271cb0ef41Sopenharmony_ci  dl_iterate_phdr(postject__dl_iterate_phdr_callback, &main_program_info);
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci  uintptr_t p = (uintptr_t)main_program_info.dlpi_phdr;
1301cb0ef41Sopenharmony_ci  size_t n = main_program_info.dlpi_phnum;
1311cb0ef41Sopenharmony_ci  uintptr_t base_addr = main_program_info.dlpi_addr;
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci  // iterate program header
1341cb0ef41Sopenharmony_ci  for (; n > 0; n--, p += sizeof(ElfW(Phdr))) {
1351cb0ef41Sopenharmony_ci    ElfW(Phdr)* phdr = (ElfW(Phdr)*)p;
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ci    // skip everything but notes
1381cb0ef41Sopenharmony_ci    if (phdr->p_type != PT_NOTE) {
1391cb0ef41Sopenharmony_ci      continue;
1401cb0ef41Sopenharmony_ci    }
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci    // note segment starts at base address + segment virtual address
1431cb0ef41Sopenharmony_ci    uintptr_t pos = (base_addr + phdr->p_vaddr);
1441cb0ef41Sopenharmony_ci    uintptr_t end = (pos + phdr->p_memsz);
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci    // iterate through segment until we reach the end
1471cb0ef41Sopenharmony_ci    while (pos < end) {
1481cb0ef41Sopenharmony_ci      if (pos + sizeof(ElfW(Nhdr)) > end) {
1491cb0ef41Sopenharmony_ci        break;  // invalid
1501cb0ef41Sopenharmony_ci      }
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_ci      ElfW(Nhdr)* note = (ElfW(Nhdr)*)(uintptr_t)pos;
1531cb0ef41Sopenharmony_ci      if (note->n_namesz != 0 && note->n_descsz != 0 &&
1541cb0ef41Sopenharmony_ci          strncmp((char*)(pos + sizeof(ElfW(Nhdr))), (char*)name,
1551cb0ef41Sopenharmony_ci                  sizeof(name)) == 0) {
1561cb0ef41Sopenharmony_ci        *size = note->n_descsz;
1571cb0ef41Sopenharmony_ci        // advance past note header and aligned name
1581cb0ef41Sopenharmony_ci        // to get to description data
1591cb0ef41Sopenharmony_ci        return (void*)((uintptr_t)note + sizeof(ElfW(Nhdr)) +
1601cb0ef41Sopenharmony_ci                       roundup(note->n_namesz, 4));
1611cb0ef41Sopenharmony_ci      }
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ci      pos += (sizeof(ElfW(Nhdr)) + roundup(note->n_namesz, 4) +
1641cb0ef41Sopenharmony_ci              roundup(note->n_descsz, 4));
1651cb0ef41Sopenharmony_ci    }
1661cb0ef41Sopenharmony_ci  }
1671cb0ef41Sopenharmony_ci  return NULL;
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_ci#elif defined(_WIN32)
1701cb0ef41Sopenharmony_ci  void* ptr = NULL;
1711cb0ef41Sopenharmony_ci  char* resource_name = NULL;
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_ci  if (options != NULL && options->pe_resource_name != NULL) {
1741cb0ef41Sopenharmony_ci    name = options->pe_resource_name;
1751cb0ef41Sopenharmony_ci  } else {
1761cb0ef41Sopenharmony_ci    // Automatically uppercase the resource name or it won't be found
1771cb0ef41Sopenharmony_ci    resource_name = (char*)malloc(strlen(name) + 1);
1781cb0ef41Sopenharmony_ci    if (resource_name == NULL) {
1791cb0ef41Sopenharmony_ci      return NULL;
1801cb0ef41Sopenharmony_ci    }
1811cb0ef41Sopenharmony_ci    strcpy_s(resource_name, strlen(name) + 1, name);
1821cb0ef41Sopenharmony_ci    CharUpperA(resource_name);  // Uppercases inplace
1831cb0ef41Sopenharmony_ci  }
1841cb0ef41Sopenharmony_ci
1851cb0ef41Sopenharmony_ci  HRSRC resource_handle =
1861cb0ef41Sopenharmony_ci      FindResourceA(NULL, resource_name != NULL ? resource_name : name,
1871cb0ef41Sopenharmony_ci                    MAKEINTRESOURCEA(10) /* RT_RCDATA */);
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_ci  if (resource_handle) {
1901cb0ef41Sopenharmony_ci    HGLOBAL global_resource_handle = LoadResource(NULL, resource_handle);
1911cb0ef41Sopenharmony_ci
1921cb0ef41Sopenharmony_ci    if (global_resource_handle) {
1931cb0ef41Sopenharmony_ci      if (size != NULL) {
1941cb0ef41Sopenharmony_ci        *size = SizeofResource(NULL, resource_handle);
1951cb0ef41Sopenharmony_ci      }
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci      ptr = LockResource(global_resource_handle);
1981cb0ef41Sopenharmony_ci    }
1991cb0ef41Sopenharmony_ci  }
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_ci  free(resource_name);
2021cb0ef41Sopenharmony_ci
2031cb0ef41Sopenharmony_ci  return ptr;
2041cb0ef41Sopenharmony_ci#else
2051cb0ef41Sopenharmony_ci  return NULL;
2061cb0ef41Sopenharmony_ci#endif
2071cb0ef41Sopenharmony_ci}
2081cb0ef41Sopenharmony_ci
2091cb0ef41Sopenharmony_ci#endif  // POSTJECT_API_H_
210