kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

read_util.c (2852B)


      1 /* Shared PE/COFF reader primitives — see read_util.h. */
      2 
      3 #include "obj/coff/read_util.h"
      4 
      5 #include <string.h>
      6 
      7 #include "obj/obj.h" /* SecKind / SecFlag enums */
      8 
      9 int coff_rva_to_offset(const u8* shdrs, u16 nsec, u32 rva, size_t len,
     10                        u64* off_out) {
     11   for (u16 i = 0; i < nsec; ++i) {
     12     const u8* sh = shdrs + (u64)i * COFF_SECTION_HEADER_SIZE;
     13     u32 vsize = coff_rd_u32(sh + 8);
     14     u32 vaddr = coff_rd_u32(sh + 12);
     15     u32 raw_size = coff_rd_u32(sh + 16);
     16     u32 raw_ptr = coff_rd_u32(sh + 20);
     17     /* Some linkers leave VirtualSize == 0 in objects; use raw_size as
     18      * a fallback so we still resolve RVAs in well-formed images. */
     19     u32 span = vsize ? vsize : raw_size;
     20     if (rva >= vaddr && rva < vaddr + span) {
     21       u64 delta = (u64)(rva - vaddr);
     22       if (delta >= raw_size) return 0; /* RVA past on-disk data */
     23       u64 off = (u64)raw_ptr + delta;
     24       if (off >= len) return 0;
     25       *off_out = off;
     26       return 1;
     27     }
     28   }
     29   return 0;
     30 }
     31 
     32 u32 coff_read_cstr(const u8* data, size_t len, u64 off, const char** out) {
     33   if (off >= len) {
     34     *out = "";
     35     return 0;
     36   }
     37   const char* s = (const char*)(data + off);
     38   u64 max = (u64)len - off;
     39   u64 n = 0;
     40   while (n < max && s[n] != '\0') ++n;
     41   if (n == max) {
     42     *out = "";
     43     return 0;
     44   } /* unterminated */
     45   *out = s;
     46   return (u32)n;
     47 }
     48 
     49 u16 coff_sec_kind(const char* name, u32 nlen, u32 ch) {
     50   if (ch & IMAGE_SCN_CNT_UNINITIALIZED_DATA) return SEC_BSS;
     51   if (ch & IMAGE_SCN_CNT_CODE) return SEC_TEXT;
     52   if (ch & IMAGE_SCN_MEM_EXECUTE) return SEC_TEXT;
     53   if (nlen >= 7 && memcmp(name, ".debug_", 7) == 0) return SEC_DEBUG;
     54   /* The MS toolchain spells DWARF section names with a leading ".debug$"
     55    * (CodeView) — keep ELF-style ".debug_" detection but also treat the
     56    * MS form as debug. */
     57   if (nlen >= 7 && memcmp(name, ".debug$", 7) == 0) return SEC_DEBUG;
     58   if (ch & IMAGE_SCN_CNT_INITIALIZED_DATA) {
     59     if (ch & IMAGE_SCN_MEM_WRITE) return SEC_DATA;
     60     return SEC_RODATA;
     61   }
     62   return SEC_OTHER;
     63 }
     64 
     65 u16 coff_sec_flags(const char* name, u32 nlen, u32 ch) {
     66   u16 f = 0;
     67   if (ch & IMAGE_SCN_MEM_READ) f |= SF_ALLOC;
     68   if (ch & IMAGE_SCN_MEM_EXECUTE) f |= SF_EXEC;
     69   if (ch & IMAGE_SCN_MEM_WRITE) f |= SF_WRITE;
     70   if (ch & IMAGE_SCN_LNK_COMDAT) f |= SF_GROUP;
     71   /* TLS sections in PE are spelled ".tls$<suffix>" (e.g. ".tls$", ".tls$ZZZ").
     72    * There is no characteristics bit for TLS — detection is name-based. */
     73   if (nlen >= 5 && memcmp(name, ".tls$", 5) == 0) f |= SF_TLS;
     74   if (nlen == 4 && memcmp(name, ".tls", 4) == 0) f |= SF_TLS;
     75   return f;
     76 }
     77 
     78 /* Bits 20..23 of Characteristics encode alignment as (log2(align)+1).
     79  * 0 means "default"; we collapse to align=1 for round-trip purposes. */
     80 u32 coff_sec_align(u32 ch) {
     81   u32 n = (ch & IMAGE_SCN_ALIGN_MASK) >> 20;
     82   if (n == 0) return 1;
     83   return 1u << (n - 1u);
     84 }