diff --git a/programs/develop/obj2def/README.md b/programs/develop/obj2def/README.md new file mode 100644 index 0000000000..1ed31ac79f --- /dev/null +++ b/programs/develop/obj2def/README.md @@ -0,0 +1,5 @@ +# clink + +Very simple (yet?) COFF to COFF linker. Merges several COFF files into one. Only works for dependency-less objects yet (designed exclusively for linking objects into KolibriOS COFF library). + +[Development process](https://www.youtube.com/playlist?list=PLVMOfciBdLI6BPovPgfVZ9bNuwbXetRc9) (in Russian) diff --git a/programs/develop/obj2def/cdict/LICENSE b/programs/develop/obj2def/cdict/LICENSE new file mode 100644 index 0000000000..b1520f0de1 --- /dev/null +++ b/programs/develop/obj2def/cdict/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Magomed Kostoev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/programs/develop/obj2def/cdict/README.md b/programs/develop/obj2def/cdict/README.md new file mode 100644 index 0000000000..fef8f3a18f --- /dev/null +++ b/programs/develop/obj2def/cdict/README.md @@ -0,0 +1,88 @@ +# CDict - a simple dictionary implementation in C +## Ready to use! + +It may be used out of the box with key and value of type `CStr` (which is `char *` - zero-terminated string). Once it instantiated in some file using `CDICT_INST` definition: + +```C +#define CDICT_INST +#include "cdict.h" +``` + +It may be then declared just using `#include`: + +```C +#include "cdict.h" + +int main() { + CDict_CStr_CStr dict; + if (!cdict_CStr_CStr_init(&dict)) { + printf("CDict returned error #%d", dict.error_code); + return 0; + } + cdict_CStr_CStr_add_vv(&dict, "key_a", "value_a", CDICT_REPLACE_EXIST); + printf("[key_a] = \"%s\"\n", cdict_CStr_CStr_get_v(&dict, "key_a")); +} +``` + +## Easy to configure! + +If you want to create a dictionary for other key types you should provide your own keys hashing and comparsion functions, in such case the instantiation of the library will look like this: + +```C +#define CDICT_INST +#define CDICT_KEY_T MyType +#define CDICT_HASH_FN(pkey) my_hash(pkey) +#define CDICT_CMP_FN(pkey0, pkey1) my_cmp(pkey0, pkey1) +#include "cdict.h" + +int my_cmp(MyType *pkey0, MyType *pkey1) { + // Return `whatever_negative` if `key0 < key1`, `0` if `key0 == key1` and `whatever_positive` if `key0 > key1` +} + +unsigned long my_hash(MyType *key) { + // Return the hash of the key +} +``` + +Then to use the new dictionary you only need to define key type before the header inclusion: + +```C +#define CDICT_KEY_T MyType +#include "cdict.h" + +// ... + CDict_MyType_CStr dict; + cdict_MyType_CStr_init(&dict); +// ... +``` + +If you want to specify the type of values - just define the type: + +```C +#define CDICT_VAL_T MyValueType +``` + +And so on. + +## Dependency-free! + +Every single used dependency may be redefined: + +```C +#define CDICT_ASSERT_FN(x) my_assert(x); +``` + +## Flexible! + +May define user data to be used in overriden functions (for example - custom allocators): + +```C +#define CDICT_USER_DATA_T UserData +#define CDICT_HASHTAB_ITEM_ALLOC_FN(cdict, size) item_alloc(cdict, size) +#define CDICT_HASHTAB_ITEM_FREE_FN(cdict, ptr) item_free(cdict, ptr) +#define CDICT_HASHTAB_ALLOC_FN(cdict, size) hashtab_alloc(cdict, size) +``` + +## Checkout + +[The library](cdict.h). diff --git a/programs/develop/obj2def/cdict/cdict.h b/programs/develop/obj2def/cdict/cdict.h new file mode 100644 index 0000000000..4d375492bf --- /dev/null +++ b/programs/develop/obj2def/cdict/cdict.h @@ -0,0 +1,350 @@ +// Copyright (c) 2020 Magomed Kostoev +// +// You may use, distribute and modify this code under the terms of the MIT license. +// +// You should have received a copy of the MIT license with this file. If not, please visit +// https://opensource.org/licenses/MIT or boppan.org/MIT for full license details. + +// cdict.h - simple dictionaty implementation in C. +// +// Uses hash table with fixed (but configurable) size. Functions named using given type names: +// cdict___. +// +// See configuration below (in public "Input macros" section), also: +// CDICT_INST: Instantiate the functions if defined. +// +// Minimal definitions for declaration: CDICT_KEY_T, CDICT_VAL_T +// Minimal definitions for instantiation: CDICT_INST, CDICT_KEY_T, CDICT_VAL_T, CDICT_HASH_FN, +// CDICT_CMP_FN +// +// WARNING: All used definitions will be undefined on header exit. +// +// Dependencies: +// or another source of size_t +// or another source of malloc, and calloc +// or another source of assert + +// +// Internal macros for external declarations +// + +#define CDICT_CAT2_IMPL(x, y) x ## _ ## y +#define CDICT_CAT2(x, y) CDICT_CAT2_IMPL(x, y) + +/// Creates method name according to CDICT_KEY_T and CDICT_VAL_T +#define CDICT_FUN(name) CDICT_CAT2(cdict, CDICT_CAT2(CDICT_KEY_T, CDICT_CAT2(CDICT_VAL_T, name))) + +#define cdict_init CDICT_FUN(init) +#define cdict_init_ud CDICT_FUN(init_ud) +#define cdict_init_pud CDICT_FUN(init_pud) +#define cdict_add_pp CDICT_FUN(add_pp) +#define cdict_add_vv CDICT_FUN(add_vv) +#define cdict_get_p CDICT_FUN(get_p) +#define cdict_get_v CDICT_FUN(get_v) +#define cdict_error_message CDICT_FUN(error_message) + +#define cdict_hash CDICT_FUN(hash) +#define cdict_keycmp CDICT_FUN(keycmp) +#define cdict_chain_begin CDICT_FUN(begin) +#define cdict_chain_next CDICT_FUN(next) + +#define CDictItem CDICT_CAT2(CDictItem, CDICT_CAT2(CDICT_KEY_T, CDICT_VAL_T)) +#define CDictItem_s CDICT_CAT2(CDictItem_s, CDICT_CAT2(CDICT_KEY_T, CDICT_VAL_T)) +#define CDict CDICT_CAT2(CDict, CDICT_CAT2(CDICT_KEY_T, CDICT_VAL_T)) + +// +// Input macros +// + +/// Type of the dictionary's keys, named type only - used in functions names, default: CStr +#ifndef CDICT_KEY_T +typedef char *CStr; +#define CDICT_CSTR_IS_THERE +#define CDICT_KEY_T CStr +#endif + +/// Type of the dictionary's values, named type only - used in functions names, default: CStr +#ifndef CDICT_VAL_T +#ifndef CDICT_CSTR_IS_THERE +typedef char *CStr; +#endif +#define CDICT_VAL_T CStr +#endif + +/// Type of user data +#ifndef CDICT_USER_DATA_T +#define CDICT_USER_DATA_T void * +#endif + +// +// Public interface +// + +#define CDICT_NO_CHECK 0 +#define CDICT_REPLACE_EXIST 1 +#define CDICT_LEAVE_EXIST 2 + +#define CDICT_ERR_SUCCESS 0 +#define CDICT_ERR_OUT_OF_MEMORY 1 +#define CDICT_ERR_THIS_IS_NULL 2 +#define CDICT_ERR_HASH_TABLE_IS_NULL 3 +#define CDICT_ERR_PKEY0_IS_NULL 4 +#define CDICT_ERR_PKEY1_IS_NULL 5 +#define CDICT_ERR_PKEY_IS_NULL 6 +#define CDICT_ERR_PVAL_IS_NULL 7 + +typedef struct CDictItem_s { + struct CDictItem_s *next_collision; + CDICT_KEY_T key; + CDICT_VAL_T val; +} CDictItem; + +typedef struct { + CDictItem **hash_table; + CDICT_USER_DATA_T user_data; + int error_code; +} CDict; + +/// Initializes dictionary structure +int cdict_init(CDict *s); + +/// Initializes dictionary structure with non-standard user data +int cdict_init_ud(CDict *s, CDICT_USER_DATA_T user_data); + +/// Initializes dictionary structure with non-standard user data +int cdict_init_pud(CDict *s, CDICT_USER_DATA_T *user_data); + +/// Inserts a value by key (receives pointers to val and key) +CDictItem *cdict_add_pp(CDict *s, CDICT_KEY_T *pkey, CDICT_VAL_T *pval, int if_exists); + +/// Inserts a value by key (receives values of val and key) +CDictItem *cdict_add_vv(CDict *s, CDICT_KEY_T key, CDICT_VAL_T val, int if_exists); + +/// Gives a value by key (receives a pointer to key) +CDICT_VAL_T cdict_get_p(CDict *s, CDICT_KEY_T *pkey); + +/// Gives a vaule by key (receives a value of key) +CDICT_VAL_T cdict_get_v(CDict *s, CDICT_KEY_T key); + +#ifdef CDICT_INST + +// +// Input macros (instantiation edition) +// + +/// The value returned on some error +#ifndef CDICT_VAL_DEFAULT +#define CDICT_VAL_DEFAULT (CDICT_VAL_T){ 0 } +#endif + +/// Hashing function for the key type +#ifndef CDICT_HASH_FN +#include +#define CDICT_HASH_FN(pkey) strlen(*pkey) ^ (*pkey)[0] +#else +#define CDICT_HASH_FN_OVERRIDEN +#endif + +/// Ammount of pointers to elements in hash table +#ifndef CDICT_HASHTAB_SZ +#define CDICT_HASHTAB_SZ 1024 +#endif + +/// Hash table allocator MUST return zeroed buffer +#ifndef CDICT_HASHTAB_ALLOC_FN +#include +#define CDICT_HASHTAB_ALLOC_FN(cdict, size) calloc(1, size) +#else +#define CDICT_HASHTAB_ALLOCATORS_OVERRIDDEN +#endif + +/// New hash table items allocator (should be just a function call) +#ifndef CDICT_HASHTAB_ITEM_ALLOC_FN +#include +#define CDICT_HASHTAB_ITEM_ALLOC_FN(cdict, size) malloc(size) +#define CDICT_HASHTAB_ITEM_FREE_FN(cdict, ptr) free(ptr) +#else +#ifndef CDICT_HASHTAB_ITEM_FREE_FN +#error "CDICT_HASHTAB_ITEM_FREE_FN should be defiend along with CDICT_HASHTAB_ITEM_ALLOC_FN" +#endif +#define CDICT_HASHTAB_ITEM_ALLOCATORS_OVERRIDDEN +#endif + +#ifdef CDICT_HASHTAB_ITEM_ALLOCATORS_OVERRIDDEN +#error "FUCK!" +#endif + +/// Replacement for assert from +#ifndef CDICT_ASSERT_FN +#include +#define CDICT_ASSERT_FN(x) if (!x) { printf(__FILE__":%d: Disasserted", __LINE__); } assert(x) +#endif + +/// Function for comparsion of keys, return should be the same as memcmp +#ifndef CDICT_CMP_FN +#include +#define CDICT_CMP_FN(pkey0, pkey1) strcmp(*pkey0, *pkey1) +#else +#define CDICT_CMP_FN_OVERRIDDEN +#endif + +// +// Internal macros (instantiation edition) +// + +#define CDICT_ASSERT(x) ({ CDICT_ASSERT_FN(x); x; }) +// Should write the error code into strucure, but should not rewrite it's already set +#define CDICT_IF_NULL_SET_ERR_RETURN(x, ec, res) if (x == NULL) { \ + if (s->error_code == CDICT_ERR_SUCCESS) s->error_code = ec; \ + return res; \ + } +#define CDICT_IF_NULL_RETURN(x, res) if (x == NULL) return res + +// +// Predeclarations +// + +#ifdef CDICT_HASHTAB_ITEM_ALLOCATORS_OVERRIDDEN +void *CDICT_HASHTAB_ITEM_ALLOC_FN(CDict *s, size_t size); +void CDICT_HASHTAB_ITEM_FREE_FN(CDict *s, CDictItem *ptr); +#endif + +#ifdef CDICT_HASHTAB_ALLOCATORS_OVERRIDDEN +void *CDICT_HASHTAB_ALLOC_FN(CDict *s, size_t size); +#endif + +#ifdef CDICT_HASH_FN_OVERRIDEN +unsigned long CDICT_HASH_FN(CDICT_KEY_T *pkey); +#endif + +#ifdef CDICT_CMP_FN_OVERRIDDEN +int CDICT_CMP_FN(CDICT_KEY_T *pkey0, CDICT_KEY_T *pkey1); +#endif + +// +// The code +// + +static size_t cdict_hash(CDICT_KEY_T *pkey) { + return CDICT_HASH_FN(CDICT_ASSERT(pkey)) & (CDICT_HASHTAB_SZ - 1); +} + +static int cdict_keycmp(CDICT_KEY_T *pkey0, CDICT_KEY_T *pkey1) { + return CDICT_CMP_FN(CDICT_ASSERT(pkey0), CDICT_ASSERT(pkey1)); +} + +static CDictItem **cdict_chain_begin(CDict *s, CDICT_KEY_T *pkey) { + CDICT_ASSERT(s); + size_t hash = cdict_hash(CDICT_ASSERT(pkey)); + CDICT_IF_NULL_SET_ERR_RETURN(s->hash_table, CDICT_ERR_HASH_TABLE_IS_NULL, NULL); + return &s->hash_table[hash]; +} + +static CDictItem **cdict_chain_next(CDictItem **ppit) { + CDICT_ASSERT(ppit); + CDICT_ASSERT(*ppit); + return &(*ppit)->next_collision; +} + +int cdict_init(CDict *s) { + return cdict_init_pud(s, NULL); +} + +int cdict_init_ud(CDict *s, CDICT_USER_DATA_T user_data) { + return cdict_init_pud(s, &user_data); +} + +int cdict_init_pud(CDict *s, CDICT_USER_DATA_T *user_data) { + CDICT_IF_NULL_RETURN(s, 0); + s->user_data = user_data ? *user_data : (CDICT_USER_DATA_T){ 0 }; + s->error_code = CDICT_ERR_SUCCESS; + s->hash_table = CDICT_HASHTAB_ALLOC_FN(s, sizeof(*s->hash_table) * CDICT_HASHTAB_SZ); + CDICT_IF_NULL_SET_ERR_RETURN(s->hash_table, CDICT_ERR_OUT_OF_MEMORY, 0); + return 1; +} + +CDictItem *cdict_add_pp(CDict *s, CDICT_KEY_T *pkey, CDICT_VAL_T *pval, int if_exists) { + CDICT_IF_NULL_RETURN(s, NULL); + CDICT_IF_NULL_SET_ERR_RETURN(pkey, CDICT_ERR_PKEY_IS_NULL, NULL); + CDICT_IF_NULL_SET_ERR_RETURN(pval, CDICT_ERR_PVAL_IS_NULL, NULL); + CDictItem *next_collision = NULL; + CDictItem **ppit = cdict_chain_begin(s, pkey); + CDICT_IF_NULL_RETURN(ppit, NULL); + while (*ppit) { + int exists = if_exists == CDICT_NO_CHECK ? 0 : !cdict_keycmp(pkey, &(*ppit)->key); + if (exists) { + if (if_exists == CDICT_LEAVE_EXIST) { + return *ppit; + } else if (if_exists == CDICT_REPLACE_EXIST) { + next_collision = (*ppit)->next_collision; + CDICT_HASHTAB_ITEM_FREE_FN(s, *ppit); + break; + } + } + ppit = cdict_chain_next(ppit); + } + *ppit = CDICT_HASHTAB_ITEM_ALLOC_FN(s, sizeof(**ppit)); + CDictItem *pit = *ppit; + pit->key = *pkey; + pit->val = *pval; + pit->next_collision = next_collision; + return pit; +} + +CDictItem *cdict_add_vv(CDict *s, CDICT_KEY_T key, CDICT_VAL_T val, int if_exists) { + return cdict_add_pp(s, &key, &val, if_exists); +} + +CDICT_VAL_T cdict_get_p(CDict *s, CDICT_KEY_T *pkey) { + CDICT_IF_NULL_RETURN(s, CDICT_VAL_DEFAULT); + CDICT_IF_NULL_SET_ERR_RETURN(pkey, CDICT_ERR_PKEY_IS_NULL, CDICT_VAL_DEFAULT); + CDictItem **ppit = cdict_chain_begin(s, pkey); + CDICT_IF_NULL_RETURN(ppit, CDICT_VAL_DEFAULT); + while (*ppit) { + if (!cdict_keycmp(pkey, &(*ppit)->key)) { + return (*ppit)->val; + } + ppit = cdict_chain_next(ppit); + } + return CDICT_VAL_DEFAULT; +} + +CDICT_VAL_T cdict_get_v(CDict *s, CDICT_KEY_T key) { + return cdict_get_p(s, &key); +} + +#endif + +#undef CDICT_CAT2_IMPL +#undef CDICT_CAT2 +#undef CDICT_FUN + +#undef cdict_init +#undef cdict_init_ud +#undef cdict_init_pud +#undef cdict_add_pp +#undef cdict_add_vv +#undef cdict_get_p +#undef cdict_get_v + +#undef CDICT_KEY_T +#undef CDICT_VAL_T +#undef CDICT_USER_DATA_T + +#ifdef CDICT_INST +#undef CDICT_INST +#undef CDICT_HASH_FN +#undef CDICT_HASHTAB_SZ +#undef CDICT_HASHTAB_ALLOC_FN +#undef CDICT_HASHTAB_ITEM_ALLOC_FN +#undef CDICT_HASHTAB_ITEM_FREE_FN +#undef CDICT_ASSERT_FN +#undef CDICT_CMP_FN +#undef CDICT_ASSERT +#undef CDICT_IF_NULL_RETURN +#undef CDICT_IF_NULL_SET_ERR_RETURN +#undef CDICT_HASHTAB_ITEM_ALLOCATORS_OVERRIDDEN +#undef CDICT_HASHTAB_ALLOCATORS_OVERRIDDEN +#undef CDICT_HASH_FN_OVERRIDEN +#undef CDICT_CMP_FN_OVERRIDDEN +#endif diff --git a/programs/develop/obj2def/cvec/LICENSE b/programs/develop/obj2def/cvec/LICENSE new file mode 100644 index 0000000000..b1520f0de1 --- /dev/null +++ b/programs/develop/obj2def/cvec/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Magomed Kostoev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/programs/develop/obj2def/cvec/README.md b/programs/develop/obj2def/cvec/README.md new file mode 100644 index 0000000000..3bdceee731 --- /dev/null +++ b/programs/develop/obj2def/cvec/README.md @@ -0,0 +1,88 @@ +# cvec - partial `std::vector` implementation in C. +## Partial implementation of `std::vector` + +Member functions table: + +| Status | Name | Function or reason if not implemented | +| :---: | --- | --- | +| :heavy_check_mark: | `(constructor)` | `new` | +| :heavy_check_mark: | `(destructor)` | `free` | +| :heavy_check_mark: | `operator=` | `assign_other` | +| :heavy_check_mark: | `assign` | `assign_fill`, `assign_range` | +| :heavy_minus_sign: | `get_allocator` | No `allocator` objects in the language | +| :heavy_check_mark: | `at` | `at` | +| :heavy_check_mark: | `operator[]` | `[]` | +| :heavy_check_mark: | `front` | `front`, `front_p` | +| :heavy_check_mark: | `back` | `back`, `back_p` | +| :heavy_check_mark: | `data` | `data` | +| :heavy_check_mark: | `begin` | `begin` | +| :heavy_check_mark: | `cbegin` | `cbegin` | +| :heavy_check_mark: | `end` | `end` | +| :heavy_check_mark: | `cend` | `cend` | +| :heavy_minus_sign: | `rbegin` | No reverse iterators in the language | +| :heavy_minus_sign: | `crbegin` | No reverse iterators in the language | +| :heavy_minus_sign: | `rend` | No reverse iterators in the language | +| :heavy_minus_sign: | `crend` | No reverse iterators in the language | +| :heavy_check_mark: | `empty` | `empty` | +| :heavy_check_mark: | `size` | `size` | +| :heavy_check_mark: | `max_size` | `max_size` | +| :heavy_check_mark: | `reserve` | `reserve` | +| :heavy_check_mark: | `capacity` | `capacity` | +| :heavy_check_mark: | `shrink_to_fit` | `shrink_to_fit` | +| :heavy_check_mark: | `clear` | `clear` | +| :heavy_check_mark: | `insert` | `insert`, `insert_it` | +| :heavy_minus_sign: | `emplace` | I know no way to preserve the original signature | +| :heavy_check_mark: | `erase` | `erase` | +| :heavy_check_mark: | `push_back` | `push_back` | +| :heavy_minus_sign: | `emplace_back` | I know no way to preserve the original signature | +| :heavy_check_mark: | `pop_back` | `pop_back` | +| :heavy_check_mark: | `resize` | `resize` | +| :heavy_minus_sign: | `swap` | Would have n complexity in this implementation | + +## Easy to use + +To use the std::vector implementation for specified type they should be declared as follows: + +```C +#define CVEC_TYPE TypeOfVectorElement +#include "cvec.h" + +// ... + + TypeOfVectorElement *vec = cvec_TypeOfVectorElement_new(128); + + cvec_TypeOfVectorElement_push_back(&vec, value); +``` + +Also somewhere in the project the functinos should be instantiated as follows: + +```C +#define CVEC_TYPE TypeOfVectorElement +#define CVEC_INST +#include "cvec.h" +``` + +## Allows using of custom allocators. + +```C +#define CVEC_TYPE pchar +#define CVEC_INST +#define CVEC_MALLOC custom_malloc +#define CVEC_REALLOC custom_realloc +#define CVEC_FREE custom_free +#include "cvec.h" +``` + +## Allows handling of exceptional cases. + +```C +#define CVEC_TYPE pchar +#define CVEC_INST +// Set Out Of Bounds handler +#define CVEC_OOBH(funcname, vec, index) printf("Out of bounds in %s (vec = %p, i = %d)", funcname, vec, index); abort(); +#include "cvec.h" +``` + +## Has no fixed dependencies + +Every function it uses may be overridden. More information about dependencies in [cvec.h](cvec.h). diff --git a/programs/develop/obj2def/cvec/cvec.h b/programs/develop/obj2def/cvec/cvec.h new file mode 100644 index 0000000000..b9a5da3227 --- /dev/null +++ b/programs/develop/obj2def/cvec/cvec.h @@ -0,0 +1,498 @@ +// Copyright (c) 2015 Evan Teran +// Copyright (c) 2020 Magomed Kostoev +// +// You may use, distribute and modify this code under the terms of the MIT license. +// +// You should have received a copy of the MIT license with this file. If not, please visit +// https://opensource.org/licenses/MIT for full license details. + +// cvec.h - std::vector (ish) implementation in C. Based on https://github.com/eteran/c-vector/. +// +// Unlike a real std::vector this one is implemented as a fat array, so metadata is placed inside +// an allocated buffer itself. +// +// Configuration (definitions): +// CVEC_TYPE: Type of the vector's elements, after instantiation these functions will be visible +// as cvec__funcname, so no stars and subscripting marks allowed - named +// types only +// CVEC_INST: Instantiate the functions if defined +// CVEC_LOGG: Multiply capacity by CVEC_LOGG each expansion if defined (should be >= 1) +// CVEC_ASSERT: Replacement for assert from +// CVEC_MALLOC: Replacement for malloc from +// CVEC_REALLOC: Replacement for realloc from +// CVEC_FREE: Replacement for free from +// CVEC_OOBH: Out-of-bounds handler (gets __func__, vector data address and index of overflow) +// CVEC_OOBVAL: Default value to return on out of bounds access +// +// Minimal definitions for declaration: CVEC_TYPE +// Minimal definitions for instantiation: CVEC_TYPE, CVEC_INST, CVEC_OOBVAL if the type object +// can't be represented by 0 value. +// +// WARNING: All used definitions will be undefined on header exit. +// +// Dependencies: +// or another source of size_t and ptrdiff_t +// or another source of SIZE_MAX +// or another source of malloc, calloc and realloc +// or another source of assert + +// +// Input macros +// + +#ifndef CVEC_LOGG +# define CVEC_LOGG 1.5 +#endif +#ifndef CVEC_ASSERT +# define CVEC_ASSERT(x) assert(x) +#endif +#ifndef CVEC_MALLOC +# define CVEC_MALLOC(size) malloc(size) +#endif +#ifndef CVEC_REALLOC +# define CVEC_REALLOC(ptr, size) realloc(ptr, size) +#endif +#ifndef CVEC_FREE +# define CVEC_FREE(size) free(size) +#endif +#ifndef CVEC_OOBH +# define CVEC_OOBH(funcname, vec, index) +#endif +#ifndef CVEC_OOBVAL +# define CVEC_OOBVAL { 0 } +#endif + +// +// Internal macros +// + +#define CVEC_CONCAT2_IMPL(x, y) cvec_ ## x ## _ ## y +#define CVEC_CONCAT2(x, y) CVEC_CONCAT2_IMPL(x, y) + +/// Creates method name according to CVEC_TYPE +#define CVEC_FUN(name) CVEC_CONCAT2(CVEC_TYPE, name) + +#define cvec_x_new CVEC_FUN(new) +#define cvec_x_capacity CVEC_FUN(capacity) +#define cvec_x_size CVEC_FUN(size) +#define cvec_x_empty CVEC_FUN(empty) +#define cvec_x_pop_back CVEC_FUN(pop_back) +#define cvec_x_erase CVEC_FUN(erase) +#define cvec_x_free CVEC_FUN(free) +#define cvec_x_begin CVEC_FUN(begin) +#define cvec_x_cbegin CVEC_FUN(cbegin) +#define cvec_x_end CVEC_FUN(end) +#define cvec_x_cend CVEC_FUN(cend) +#define cvec_x_push_back CVEC_FUN(push_back) +#define cvec_x_at CVEC_FUN(at) +#define cvec_x_reserve CVEC_FUN(reserve) +#define cvec_x_shrink_to_fit CVEC_FUN(shrink_to_fit) +#define cvec_x_assign_fill CVEC_FUN(assign_fill) +#define cvec_x_assign_range CVEC_FUN(assign_range) +#define cvec_x_assign_other CVEC_FUN(assign_other) +#define cvec_x_data CVEC_FUN(data) +#define cvec_x_resize CVEC_FUN(resize) +#define cvec_x_resize_v CVEC_FUN(resize_v) +#define cvec_x_clear CVEC_FUN(clear) +#define cvec_x_front CVEC_FUN(front) +#define cvec_x_front_p CVEC_FUN(front_p) +#define cvec_x_back CVEC_FUN(back) +#define cvec_x_back_p CVEC_FUN(back_p) +#define cvec_x_max_size CVEC_FUN(max_size) +#define cvec_x_insert CVEC_FUN(insert) +#define cvec_x_insert_it CVEC_FUN(insert_it) + +#define cvec_x_grow CVEC_FUN(grow) +#define cvec_x_set_capacity CVEC_FUN(set_capacity) +#define cvec_x_set_size CVEC_FUN(set_size) + +// +// External declarations +// + +/// Allocates new vector of specified capacity. +CVEC_TYPE *cvec_x_new(size_t count); + +/// Gets the current capacity of the vector. +size_t cvec_x_capacity(CVEC_TYPE **vec); + +/// Gets the current size of the vector. +size_t cvec_x_size(CVEC_TYPE **vec); + +/// Returns non-zero if the vector is empty. +int cvec_x_empty(CVEC_TYPE **vec); + +/// Removes the last element from the vector. +void cvec_x_pop_back(CVEC_TYPE **vec); + +/// Removes the element at index i from the vector. +void cvec_x_erase(CVEC_TYPE **vec, size_t i); + +/// Frees all memory associated with the vector. +void cvec_x_free(CVEC_TYPE **vec); + +/// Returns an iterator to first element of the vector. +CVEC_TYPE *cvec_x_begin(CVEC_TYPE **vec); + +/// Returns a const iterator to first element of the vector +const CVEC_TYPE *cvec_x_cbegin(CVEC_TYPE **vec); + +/// Returns an iterator to one past the last element of the vector. +CVEC_TYPE *cvec_x_end(CVEC_TYPE **vec); + +/// Returns a const iterator to one past the last element of the vector. +const CVEC_TYPE *cvec_x_cend(CVEC_TYPE **vec); + +/// Adds an element to the end of the vector. +void cvec_x_push_back(CVEC_TYPE **vec, CVEC_TYPE value); + +/// Gets element with bounds checking. On out of bounds calls CVEC_OOBH and returns CVEC_OOBVAL. +CVEC_TYPE cvec_x_at(CVEC_TYPE **vec, size_t i); + +/// Increases the capacity of the vector to a value that's equal to new_cap. +void cvec_x_reserve(CVEC_TYPE **vec, size_t new_cap); + +/// Requests the removal of unused capacity. +void cvec_x_shrink_to_fit(CVEC_TYPE **vec); + +/// Replaces the contents with count copies of value value. +void cvec_x_assign_fill(CVEC_TYPE **vec, size_t count, CVEC_TYPE value); + +/// Replaces the contents with data from range [first, last). +void cvec_x_assign_range(CVEC_TYPE **vec, CVEC_TYPE *first, CVEC_TYPE *last); + +/// Replaces the contents with contetns of other. +void cvec_x_assign_other(CVEC_TYPE **vec, CVEC_TYPE **other); + +/// Gives direct access to buffer. +CVEC_TYPE *cvec_x_data(CVEC_TYPE **vec); + +/// Resizes the container to contain count elements. +void cvec_x_resize(CVEC_TYPE **vec, size_t new_size); + +/// Resizes the container to contain count elements, initializes new elements by value. +void cvec_x_resize_v(CVEC_TYPE **vec, size_t new_size, CVEC_TYPE value); + +/// Erases all elements from the container. +void cvec_x_clear(CVEC_TYPE **vec); + +/// Returns the first element of the vector. +CVEC_TYPE cvec_x_front(CVEC_TYPE **vec); + +/// Returns a pointer to the first element of the vector. +CVEC_TYPE *cvec_x_front_p(CVEC_TYPE **vec); + +/// Returns the last element of the vector. +CVEC_TYPE cvec_x_back(CVEC_TYPE **vec); + +/// Returns a pointer to the last element of the vector. +CVEC_TYPE *cvec_x_back_p(CVEC_TYPE **vec); + +/// Returns maximal size of the vector. +size_t cvec_x_max_size(CVEC_TYPE **vec); + +/// Inserts a value into vector by index. +CVEC_TYPE *cvec_x_insert(CVEC_TYPE **vec, size_t index, CVEC_TYPE value); + +/// Inserts a value into vector by iterator (pointer in vector). +CVEC_TYPE *cvec_x_insert_it(CVEC_TYPE **vec, CVEC_TYPE *it, CVEC_TYPE value); + +// +// Function definitions +// + +#ifdef CVEC_INST + +/// Ensures that the vector is at least elements big. +static void cvec_x_grow(CVEC_TYPE **vec, size_t count); + +/// Sets the capacity variable of the vector. +static void cvec_x_set_capacity(CVEC_TYPE **vec, size_t size); + +/// Sets the size variable of the vector. +static void cvec_x_set_size(CVEC_TYPE **vec, size_t size); + +// +// Public functions +// + +CVEC_TYPE *cvec_x_new(size_t count) { + const size_t cv_sz = count * sizeof(CVEC_TYPE) + sizeof(size_t) * 2; + size_t *cv_p = CVEC_MALLOC(cv_sz); + CVEC_ASSERT(cv_p); + CVEC_TYPE *vec = (void *)(&cv_p[2]); + cvec_x_set_capacity(&vec, count); + cvec_x_set_size(&vec, 0); + return vec; +} + +size_t cvec_x_capacity(CVEC_TYPE **vec) { + CVEC_ASSERT(vec); + return *vec ? ((size_t *)*vec)[-1] : (size_t)0; +} + +size_t cvec_x_size(CVEC_TYPE **vec) { + CVEC_ASSERT(vec); + return *vec ? ((size_t *)*vec)[-2] : (size_t)0; +} + +int cvec_x_empty(CVEC_TYPE **vec) { + return cvec_x_size(vec) == 0; +} + +void cvec_x_pop_back(CVEC_TYPE **vec) { + cvec_x_set_size(vec, cvec_x_size(vec) - 1); +} + +void cvec_x_erase(CVEC_TYPE **vec, size_t i) { + CVEC_ASSERT(vec); + if (*vec) { + const size_t cv_sz = cvec_x_size(vec); + if (i < cv_sz) { + cvec_x_set_size(vec, cv_sz - 1); + for (size_t cv_x = i; cv_x < (cv_sz - 1); ++cv_x) { + (*vec)[cv_x] = (*vec)[cv_x + 1]; + } + } + } +} + +void cvec_x_free(CVEC_TYPE **vec) { + CVEC_ASSERT(vec); + if (*vec) { + size_t *p1 = &((size_t *)*vec)[-2]; + CVEC_FREE(p1); + } +} + +CVEC_TYPE *cvec_x_begin(CVEC_TYPE **vec) { + CVEC_ASSERT(vec); + return *vec; +} + +const CVEC_TYPE *cvec_x_cbegin(CVEC_TYPE **vec) { + return cvec_x_begin(vec); +} + +CVEC_TYPE *cvec_x_end(CVEC_TYPE **vec) { + CVEC_ASSERT(vec); + return *vec ? &((*vec)[cvec_x_size(vec)]) : NULL; +} + +const CVEC_TYPE *cvec_x_cend(CVEC_TYPE **vec) { + return cvec_x_end(vec); +} + +void cvec_x_push_back(CVEC_TYPE **vec, CVEC_TYPE value) { + CVEC_ASSERT(vec); + size_t cv_cap = cvec_x_capacity(vec); + if (cv_cap <= cvec_x_size(vec)) { + cvec_x_grow(vec, cv_cap * CVEC_LOGG + 1); + } + (*vec)[cvec_x_size(vec)] = value; + cvec_x_set_size(vec, cvec_x_size(vec) + 1); +} + +CVEC_TYPE cvec_x_at(CVEC_TYPE **vec, size_t i) { + CVEC_ASSERT(vec); + if (i >= cvec_x_size(vec) || i < 0) { + CVEC_OOBH(__func__, vec, i); + CVEC_TYPE ret = CVEC_OOBVAL; + return ret; + } + return (*vec)[i]; +} + +void cvec_x_reserve(CVEC_TYPE **vec, size_t new_cap) { + if (new_cap <= cvec_x_capacity(vec)) { + return; + } + cvec_x_grow(vec, new_cap); +} + +void cvec_x_shrink_to_fit(CVEC_TYPE **vec) { + if (cvec_x_capacity(vec) > cvec_x_size(vec)) { + cvec_x_grow(vec, cvec_x_size(vec)); + } +} + +void cvec_x_assign_fill(CVEC_TYPE **vec, size_t count, CVEC_TYPE value) { + CVEC_ASSERT(vec); + cvec_x_reserve(vec, count); + cvec_x_set_size(vec, count); // If the buffer was bigger than new_cap, set size ourselves + for (size_t i = 0; i < count; i++) { + (*vec)[i] = value; + } +} + +void cvec_x_assign_range(CVEC_TYPE **vec, CVEC_TYPE *first, CVEC_TYPE *last) { + CVEC_ASSERT(vec); + size_t new_size = ((ptrdiff_t)(last - first)) / sizeof(*first); + cvec_x_reserve(vec, new_size); + cvec_x_set_size(vec, new_size); + size_t i = 0; + for (CVEC_TYPE *it = first; it < last; it++, i++) { + (*vec)[i] = *it; + } +} + +void cvec_x_assign_other(CVEC_TYPE **vec, CVEC_TYPE **other) { + cvec_x_assign_range(vec, cvec_x_begin(other), cvec_x_end(other)); +} + +CVEC_TYPE *cvec_x_data(CVEC_TYPE **vec) { + CVEC_ASSERT(vec); + return (*vec); +} + +void cvec_x_resize(CVEC_TYPE **vec, size_t count) { + CVEC_TYPE value = { 0 }; + cvec_x_resize_v(vec, count, value); +} + +void cvec_x_resize_v(CVEC_TYPE **vec, size_t count, CVEC_TYPE value) { + CVEC_ASSERT(vec); + size_t old_size = cvec_x_size(vec); + cvec_x_set_size(vec, count); + if (cvec_x_capacity(vec) < count) { + cvec_x_reserve(vec, count); + for (CVEC_TYPE *it = (*vec) + old_size; it < cvec_x_end(vec); it++) { + *it = value; + } + } +} + +void cvec_x_clear(CVEC_TYPE **vec) { + cvec_x_set_size(vec, 0); +} + +CVEC_TYPE cvec_x_front(CVEC_TYPE **vec) { + CVEC_ASSERT(vec); + return (*vec)[0]; +} + +CVEC_TYPE *cvec_x_front_p(CVEC_TYPE **vec) { + CVEC_ASSERT(vec); + return (*vec); +} + +CVEC_TYPE cvec_x_back(CVEC_TYPE **vec) { + return cvec_x_end(vec)[-1]; +} + +CVEC_TYPE *cvec_x_back_p(CVEC_TYPE **vec) { + return cvec_x_end(vec) - 1; +} + +size_t cvec_x_max_size(CVEC_TYPE **vec) { + return SIZE_MAX / sizeof(**vec); +} + +CVEC_TYPE *cvec_x_insert(CVEC_TYPE **vec, size_t index, CVEC_TYPE value) { + CVEC_ASSERT(vec); + if (index > cvec_x_size(vec) || index < 0) { + return NULL; // TODO: What? + } + size_t new_size = cvec_x_size(vec) + 1; + cvec_x_reserve(vec, new_size); + cvec_x_set_size(vec, new_size); + CVEC_TYPE *ret = *vec + index; + for (CVEC_TYPE *it = cvec_x_back_p(vec); it > ret; it--) { + *it = it[-1]; + } + *ret = value; + return ret; +} + +CVEC_TYPE *cvec_x_insert_it(CVEC_TYPE **vec, CVEC_TYPE *it, CVEC_TYPE value) { + CVEC_ASSERT(vec); + size_t index = (it - *vec) / sizeof(**vec); + return cvec_x_insert(vec, index, value); +} + +// +// Private functions +// + +static void cvec_x_set_capacity(CVEC_TYPE **vec, size_t size) { + CVEC_ASSERT(vec); + if (*vec) { + ((size_t *)*vec)[-1] = size; + } +} + +static void cvec_x_set_size(CVEC_TYPE **vec, size_t size) { + CVEC_ASSERT(vec); + if (*vec) { + ((size_t *)*vec)[-2] = size; + } +} + +static void cvec_x_grow(CVEC_TYPE **vec, size_t count) { + CVEC_ASSERT(vec); + const size_t cv_sz = count * sizeof(**vec) + sizeof(size_t) * 2; + size_t *cv_p1 = &((size_t *)*vec)[-2]; + size_t *cv_p2 = CVEC_REALLOC(cv_p1, (cv_sz)); + CVEC_ASSERT(cv_p2); + *vec = (void *)(&cv_p2[2]); + cvec_x_set_capacity(vec, count); +} + +#endif + +#undef CVEC_TYPE + +#ifdef CVEC_INST +# undef CVEC_INST +# ifdef CVEC_LOGG +# undef CVEC_LOGG +# endif +# ifdef CVEC_OOBH +# undef CVEC_OOBH +# endif +# ifdef CVEC_OOBVAL +# undef CVEC_OOBVAL +# endif +# undef CVEC_ASSERT +# undef CVEC_MALLOC +# undef CVEC_REALLOC +# undef CVEC_FREE +#endif + +#undef CVEC_CONCAT2_IMPL +#undef CVEC_CONCAT2 + +#undef CVEC_FUN + +#undef cvec_x_new +#undef cvec_x_capacity +#undef cvec_x_size +#undef cvec_x_empty +#undef cvec_x_pop_back +#undef cvec_x_erase +#undef cvec_x_free +#undef cvec_x_begin +#undef cvec_x_cbegin +#undef cvec_x_end +#undef cvec_x_cend +#undef cvec_x_push_back +#undef cvec_x_at +#undef cvec_x_reserve +#undef cvec_x_shrink_to_fit +#undef cvec_x_assign_fill +#undef cvec_x_assign_range +#undef cvec_x_assign_other +#undef cvec_x_data +#undef cvec_x_resize +#undef cvec_x_resize_v +#undef cvec_x_clear +#undef cvec_x_front +#undef cvec_x_front_p +#undef cvec_x_back +#undef cvec_x_back_p +#undef cvec_x_max_size +#undef cvec_x_insert +#undef cvec_x_insert_it +#undef cvec_x_grow +#undef cvec_x_set_capacity +#undef cvec_x_set_size diff --git a/programs/develop/obj2def/epep/LICENSE b/programs/develop/obj2def/epep/LICENSE new file mode 100644 index 0000000000..b1520f0de1 --- /dev/null +++ b/programs/develop/obj2def/epep/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Magomed Kostoev + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/programs/develop/obj2def/epep/README.md b/programs/develop/obj2def/epep/README.md new file mode 100644 index 0000000000..21b09d4346 --- /dev/null +++ b/programs/develop/obj2def/epep/README.md @@ -0,0 +1,26 @@ +# epep - Embeddable PE Parser +## Features + +- PE header (including Data Directories as a part Optional Header) +- Section Headers +- COFF Symbols +- COFF Relocations +- COFF Linenumbers +- Imports +- Exports +- Base relocations (DLL) + +## How to use + +To declare functions from the library include it: + +```C +#include "epep.h" +``` + +The functions they shoud be instantiated somewhere in the project like so: + +```C +#define EPEP_INST +#include "epep.h" +``` diff --git a/programs/develop/obj2def/epep/epep.h b/programs/develop/obj2def/epep/epep.h new file mode 100644 index 0000000000..9443b2e5ce --- /dev/null +++ b/programs/develop/obj2def/epep/epep.h @@ -0,0 +1,1022 @@ +// Dependencies: +// or any another source of assert() +// or any another source of uint64_t, uint32_t, uint16_t, uint8_t, size_t + +#ifndef EPEP_ASSERT +#include +#define EPEP_ASSERT(x) assert(x) +#endif + +#ifndef EPEP_READER +#include +#define EPEP_READER FILE * +#define EPEP_READER_GET(preader) getc(*preader) +#define EPEP_READER_SEEK(preader, offset) fseek(*preader, offset, SEEK_SET) +#define EPEP_READER_SEEK_END(preader, offset) fseek(*preader, offset, SEEK_END) +#define EPEP_READER_TELL(preader) ftell(*preader) +#define EPEP_READER_GET_BLOCK(preader, size, buf) fread(buf, 1, size, *preader); +#endif + +// +// Constants +// + +typedef enum { + EPEP_INVALID, + EPEP_IMAGE, + EPEP_OBJECT, +} EpepKind; + +typedef enum { + EPEP_ERR_SUCCESS, + EPEP_ERR_DATA_DIRECTORY_INDEX_IS_INVALID, + EPEP_ERR_SECTION_HEADER_INDEX_IS_INVALID, + EPEP_ERR_SYMBOL_INDEX_IS_INVALID, + EPEP_ERR_NOT_AN_OBJECT, + EPEP_ERR_ADDRESS_IS_OUT_OF_SECTION_RAW_DATA, + EPEP_ERR_OUTPUT_CAPACITY_IS_ZERO, + EPEP_ERR_OUTPUT_IS_NULL, + EPEP_ERR_ADDRESS_IS_OUT_OF_ANY_SECTION, + EPEP_ERR_EXPORT_ADDRESS_TABLE_ENTRY_NAME_NOT_FOUND, + EPEP_ERR_NO_BASE_RELOCATION_TABLE, + EPEP_ERR_BASE_RELOCATION_IS_ALREADY_END, + EPEP_ERR_INVALID_DATA_DIRECTORY_OFFSET, + EPEP_ERR_INVALID_SECTION_HEADER_OFFSET, + EPEP_ERR_INVALID_SECTION_DATA_OFFSET, + EPEP_ERR_INVALID_STRING_TABLE_SIZE_OFFSET, + EPEP_ERR_INVALID_SYMBOL_OFFSET, + EPEP_ERR_INVALID_IMPORT_DIRECTORY_OFFSET, + EPEP_ERR_INVALID_IMPORT_DIRECTORY_NAME_OFFSET, + EPEP_ERR_INVALID_LOOKUP_OFFSET, + EPEP_ERR_INVALID_LOOKUP_NAME_OFFSET, + EPEP_ERR_INVALID_EXPORT_TABLE_OFFSET, + EPEP_ERR_INVALID_DLL_NAME_OFFSET, + EPEP_ERR_INVALID_EXPORT_NAME_POINTER_OFFSET, + EPEP_ERR_INVALID_ORDINAL_TABLE_OFFSET, + EPEP_ERR_INVALID_EXPORT_NAME_OFFSET, + EPEP_ERR_INVALID_EXPORT_ADDRESS_OFFSET, + EPEP_ERR_INVALID_FORWARDER_OFFSET, + EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_OFFSET, + EPEP_ERR_INVALID_NEXT_BASE_RELOCATION_BLOCK_OFFSET, + EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_BASE_RELOCATION_OFFSET, + EPEP_ERR_INVALID_SECTION_RELOCATION_OFFSET, + EPEP_ERR_INVALID_LINENUMBER_OFFSET, +} EpepError; + +// +// Generic +// + +typedef struct { + EPEP_READER reader; + EpepKind kind; + EpepError error_code; + size_t file_size; + size_t signature_offset_offset; + size_t signature_offset; + size_t first_data_directory_offset; + size_t first_section_header_offset; + size_t export_table_offset; + size_t import_table_offset; + size_t base_relocation_table_offset; + size_t base_relocation_table_end_offset; + struct { + uint16_t Machine; + uint16_t NumberOfSections; + uint32_t TimeDateStamp; + uint32_t PointerToSymbolTable; + uint32_t NumberOfSymbols; + uint16_t SizeOfOptionalHeader; + uint16_t Characteristics; + } coffFileHeader; + struct { + // Standard fields + uint16_t Magic; + uint8_t MajorLinkerVersion; + uint8_t MinorLinkerVersion; + uint32_t SizeOfCode; + uint32_t SizeOfInitializedData; + uint32_t SizeOfUninitializedData; + uint32_t AddressOfEntryPoint; + uint32_t BaseOfCode; + uint32_t BaseOfData; // PE32-only + // Windows-specific fields + uint64_t ImageBase; + uint32_t SectionAlignment; + uint32_t FileAlignment; + uint16_t MajorOperatingSystemVersion; + uint16_t MinorOperatingSystemVersion; + uint16_t MajorImageVersion; + uint16_t MinorImageVersion; + uint16_t MajorSubsystemVersion; + uint16_t MinorSubsystemVersion; + uint32_t Win32VersionValue; + uint32_t SizeOfImage; + uint32_t SizeOfHeaders; + uint32_t CheckSum; + uint16_t Subsystem; + uint16_t DllCharacteristics; + uint64_t SizeOfStackReserve; + uint64_t SizeOfStackCommit; + uint64_t SizeOfHeapReserve; + uint64_t SizeOfHeapCommit; + uint32_t LoaderFlags; + uint32_t NumberOfRvaAndSizes; + } optionalHeader; + struct { + uint32_t ExportFlags; + uint32_t TimeDateStamp; + uint16_t MajorVersion; + uint16_t MinorVersion; + uint32_t NameRva; + uint32_t OrdinalBase; + uint32_t AddressTableEntries; + uint32_t NumberOfNamePointers; + uint32_t ExportAddressTableRva; + uint32_t NamePointerRva; + uint32_t OrdinalTableRva; + } export_directory; +} Epep; + +/// Constructor of the general information container +int epep_init(Epep *epep, EPEP_READER reader); + +/// Gives file offset corresponding to RVA is any, returns 0 othervice +int epep_get_file_offset_by_rva(Epep *epep, size_t *offset, size_t addr); + +// +// Data Directories +// + +typedef struct { + uint32_t VirtualAddress; + uint32_t Size; +} EpepImageDataDirectory; + +/// Gives Data Directiry by its index +int epep_get_data_directory_by_index(Epep *epep, EpepImageDataDirectory *idd, size_t index); + +// +// Sections +// + +typedef struct { + char Name[8]; + uint32_t VirtualSize; + uint32_t VirtualAddress; + uint32_t SizeOfRawData; + uint32_t PointerToRawData; + uint32_t PointerToRelocations; + uint32_t PointerToLinenumbers; + uint16_t NumberOfRelocations; + uint16_t NumberOfLinenumbers; + uint32_t Characteristics; +} EpepSectionHeader; + +/// Gives Section Header by its index +int epep_get_section_header_by_index(Epep *epep, EpepSectionHeader *sh, size_t index); + +/// Gives section header by RVA +int epep_get_section_header_by_rva(Epep *epep, EpepSectionHeader *sh, size_t addr); + +/// Gives section contents by Section Header +int epep_get_section_contents(Epep *epep, EpepSectionHeader *sh, void *buf); + +// +// COFF Symbols (object file symbols) +// + +typedef union { + struct { + union { + char ShortName[8]; + struct { + uint32_t Zeroes; + uint32_t Offset; + }; + }; + uint32_t Value; + uint16_t SectionNumber; + uint16_t Type; + uint8_t StorageClass; + uint8_t NumberOfAuxSymbols; + } symbol; + struct { + uint32_t TagIndex; + uint32_t TotalSize; + uint32_t PointerToLinenumber; + uint32_t PointerToNextFunction; + uint16_t Unused; + } auxFunctionDefinition; + struct { + uint8_t Unused0[4]; + uint16_t Linenumber; + uint8_t Unused1[6]; + uint32_t PointerToNextFunction; + uint8_t Unused2[2]; + } auxBfOrEfSymbol; + struct { + uint32_t TagIndex; + uint32_t Characteristics; + uint8_t Unused[10]; + } auxWeakExternal; + struct { + char FileName[18]; + } auxFile; + struct { + uint32_t Length; + uint16_t NumberOfRelocations; + uint16_t NumberOfLinenumbers; + uint32_t CheckSum; + uint16_t Number; + uint8_t Selection; + uint8_t Unused[3]; + } auxSectionDefinition; +} EpepCoffSymbol; + +/// Gives COFF string table size +int epep_get_string_table_size(Epep *epep, size_t *size); + +/// Gives COFF string table +int epep_get_string_table(Epep *epep, char *string_table); + +/// Gives COFF Symbol by its index +int epep_get_symbol_by_index(Epep *epep, EpepCoffSymbol *sym, size_t index); + +// +// Imports +// + +typedef struct { + uint32_t ImportLookupTableRva; + uint32_t TimeDateStamp; + uint32_t ForwarderChain; + uint32_t NameRva; + uint32_t ImportAddressTableRva; +} EpepImportDirectory; + +/// Returns non-zero if import table exists in the file +int epep_has_import_table(Epep *epep); + +/// Places offset of import table into epep structure +int epep_read_import_table_offset(Epep *epep); + +/// Gives Import Directory by index +int epep_get_import_directory_by_index(Epep *epep, EpepImportDirectory *import_directory, size_t index); + +/// Gives name of Import Directory (library) +int epep_get_import_directory_name_s(Epep *epep, EpepImportDirectory *import_directory, char *name, size_t name_max); + +/// Gives Import Lookup (imported symbol) by import directory and index +int epep_get_import_directory_lookup_by_index(Epep *epep, EpepImportDirectory *import_directory, size_t *lookup, size_t index); + +/// Gives name of Import Directory Lookup (imported symbol) or nothing if imported by ordinal +int epep_get_lookup_name_s(Epep *epep, size_t lookup, char *name, size_t name_max); + +// +// Exports +// + +typedef union { + uint32_t ExportRva; + uint32_t ForwarderRva; +} EpepExportAddress; + +/// Returns non-zero if export table exists in the file +int epep_has_export_table(Epep *epep); + +/// Palces offset of export table into epep structrue +int epep_read_export_table_offset(Epep *epep); + +/// Palces export table into epep structrue +//! Needs to be called before next export functions +int epep_read_export_directory(Epep *epep); + +/// Gives name of the DLL +//! epep_read_export_directory needs to be called before +int epep_get_dll_name_s(Epep *epep, char *name, size_t name_max); + +/// Gives entry from Export Name Pointer Table by its index +//! epep_read_export_directory needs to be called before +int epep_get_export_name_pointer_by_index(Epep *epep, size_t *name_rva, size_t index); + +/// Gives export name by its index in Export Address Table (receives name buffer length) +//! epep_read_export_directory needs to be called before +int epep_get_export_name_s_by_index(Epep *epep, char *name, size_t name_max, size_t index); + +/// Gives export address by its index in Export Address Table +//! epep_read_export_directory needs to be called before +int epep_get_export_address_by_index(Epep *epep, EpepExportAddress *export_address, size_t index); + +/// Gives forwarder string of Export Address +//! epep_read_export_directory needs to be called before +int epep_get_export_address_forwarder_s(Epep *epep, EpepExportAddress *export_address, char *forwarder, size_t forwarder_max); + +/// Returns non-zero if the export address specifies forwarder string +//! epep_read_export_directory needs to be called before +int epep_export_address_is_forwarder(Epep *epep, EpepExportAddress *export_address); + +// +// DLL Base Relocations +// + +typedef struct { + size_t offset; + uint32_t PageRva; + uint32_t BlockSize; + uint16_t BaseRelocation[0]; +} EpepBaseRelocationBlock; + +typedef union { + struct { + uint16_t Offset: 12, + Type: 4; + }; + uint16_t u16; +} EpepBaseRelocation; + +/// Returns non-zero if the file contains Base Relocations +int epep_has_base_relocation_table(Epep *epep); + +/// Places offset to Base Relocation Table into epep structure +int epep_read_base_relocation_table_offset(Epep *epep); + +/// Gives first Base Relocation Block +int epep_get_first_base_relocation_block(Epep *epep, EpepBaseRelocationBlock *brb); + +/// Gives next Base Relocation Block (replaces contents of the given block) +int epep_get_next_base_relocation_block(Epep *epep, EpepBaseRelocationBlock *it); + +/// Gives Base Relocation by its index in Base Relocation Block +int epep_get_base_relocation_block_base_relocation_by_index(Epep *epep, EpepBaseRelocationBlock *brb, EpepBaseRelocation *br, size_t index); + +// +// COFF Relocations +// + +typedef struct { + uint32_t VirtualAddress; + uint32_t SymbolTableIndex; + uint16_t Type; +} EpepCoffRelocation; + +int epep_get_section_relocation_by_index(Epep *epep, EpepSectionHeader *sh, EpepCoffRelocation *rel, size_t index); + +// +// COFF Line Numbers +// + +typedef struct { + union { + uint32_t SymbolTableIndex; + uint32_t VirtualAddress; + } Type; + uint16_t Linenumber; +} EpepCoffLinenumber; + +int epep_get_section_line_number_by_index(Epep *epep, EpepSectionHeader *sh, EpepCoffLinenumber *ln, size_t index); + +#ifdef EPEP_INST + +// +// Private functions +// + +static int epep_seek(Epep *epep, size_t offset) { + EPEP_READER_SEEK(&epep->reader, offset); + return 1; +} + +static int epep_seek_end(Epep *epep, size_t offset) { + EPEP_READER_SEEK_END(&epep->reader, offset); + return 1; +} + +static int epep_read_block(Epep *epep, size_t size, void *block) { + EPEP_READER_GET_BLOCK(&epep->reader, size, block); + return 1; +} + +static int is_pe32(Epep *epep) { + return epep->optionalHeader.Magic == 0x10b; +} + +static int is_pe32p(Epep *epep) { + return epep->optionalHeader.Magic == 0x20b; +} + +static uint8_t epep_read_u8(Epep *epep) { + return EPEP_READER_GET(&epep->reader); +} + +static uint16_t epep_read_u16(Epep *epep) { + unsigned l = epep_read_u8(epep); + unsigned h = epep_read_u8(epep); + return l | (h << 8); +} + +static uint32_t epep_read_u32(Epep *epep) { + unsigned b0 = epep_read_u8(epep); + unsigned b1 = epep_read_u8(epep); + unsigned b2 = epep_read_u8(epep); + unsigned b3 = epep_read_u8(epep); + return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); +} + +static uint64_t epep_read_u64(Epep *epep) { + uint64_t res = 0; + for (unsigned i = 0; i < 64; i += 8) { + res |= epep_read_u8(epep) << i; + } + return res; +} + +static uint64_t epep_read_ptr(Epep *epep) { + return is_pe32(epep) ? epep_read_u32(epep) : epep_read_u64(epep); +} + +static int epep_valid_offset(Epep *epep, size_t offset, size_t size) { + return (offset + size) <= epep->file_size; +} + +// +// Generic +// + +int epep_init(Epep *epep, EPEP_READER reader) { + *epep = (Epep){ 0 }; + epep->kind = EPEP_IMAGE; + epep->reader = reader; + epep_seek_end(epep, 0); + epep->file_size = EPEP_READER_TELL(&epep->reader); + epep_seek(epep, 0); + epep->error_code = EPEP_ERR_SUCCESS; + epep->signature_offset_offset = 0x3c; + epep_seek(epep, epep->signature_offset_offset); + epep->signature_offset = epep_read_u32(epep); + epep_seek(epep, epep->signature_offset); + char signature_buf[4]; + signature_buf[0] = epep_read_u8(epep); + signature_buf[1] = epep_read_u8(epep); + signature_buf[2] = epep_read_u8(epep); + signature_buf[3] = epep_read_u8(epep); + if (signature_buf[0] != 'P' || signature_buf[1] != 'E' || + signature_buf[2] != '\0' || signature_buf[3] != '\0') { + epep->kind = EPEP_OBJECT; + epep_seek(epep, 0); + } + epep->coffFileHeader.Machine = epep_read_u16(epep); + epep->coffFileHeader.NumberOfSections = epep_read_u16(epep); + epep->coffFileHeader.TimeDateStamp = epep_read_u32(epep); + epep->coffFileHeader.PointerToSymbolTable = epep_read_u32(epep); + epep->coffFileHeader.NumberOfSymbols = epep_read_u32(epep); + epep->coffFileHeader.SizeOfOptionalHeader = epep_read_u16(epep); + epep->coffFileHeader.Characteristics = epep_read_u16(epep); + if (epep->coffFileHeader.SizeOfOptionalHeader != 0) { + // Standard fields + epep->optionalHeader.Magic = epep_read_u16(epep); + epep->optionalHeader.MajorLinkerVersion = epep_read_u8(epep); + epep->optionalHeader.MinorLinkerVersion = epep_read_u8(epep); + epep->optionalHeader.SizeOfCode = epep_read_u32(epep); + epep->optionalHeader.SizeOfInitializedData = epep_read_u32(epep); + epep->optionalHeader.SizeOfUninitializedData = epep_read_u32(epep); + epep->optionalHeader.AddressOfEntryPoint = epep_read_u32(epep); + epep->optionalHeader.BaseOfCode = epep_read_u32(epep); + if (is_pe32(epep)) { + epep->optionalHeader.BaseOfData = epep_read_u32(epep); + } + // Windows-specific fields + epep->optionalHeader.ImageBase = epep_read_ptr(epep); + epep->optionalHeader.SectionAlignment = epep_read_u32(epep); + epep->optionalHeader.FileAlignment = epep_read_u32(epep); + epep->optionalHeader.MajorOperatingSystemVersion = epep_read_u16(epep); + epep->optionalHeader.MinorOperatingSystemVersion = epep_read_u16(epep); + epep->optionalHeader.MajorImageVersion = epep_read_u16(epep); + epep->optionalHeader.MinorImageVersion = epep_read_u16(epep); + epep->optionalHeader.MajorSubsystemVersion = epep_read_u16(epep); + epep->optionalHeader.Win32VersionValue = epep_read_u32(epep); + epep->optionalHeader.MinorSubsystemVersion = epep_read_u16(epep); + epep->optionalHeader.SizeOfImage = epep_read_u32(epep); + epep->optionalHeader.SizeOfHeaders = epep_read_u32(epep); + epep->optionalHeader.CheckSum = epep_read_u32(epep); + epep->optionalHeader.Subsystem = epep_read_u16(epep); + epep->optionalHeader.DllCharacteristics = epep_read_u16(epep); + epep->optionalHeader.SizeOfStackReserve = epep_read_ptr(epep); + epep->optionalHeader.SizeOfStackCommit = epep_read_ptr(epep); + epep->optionalHeader.SizeOfHeapReserve = epep_read_ptr(epep); + epep->optionalHeader.SizeOfHeapCommit = epep_read_ptr(epep); + epep->optionalHeader.LoaderFlags = epep_read_u32(epep); + epep->optionalHeader.NumberOfRvaAndSizes = epep_read_u32(epep); + epep->first_data_directory_offset = EPEP_READER_TELL(&epep->reader); + } + epep->first_section_header_offset = EPEP_READER_TELL(&epep->reader); + if (epep->coffFileHeader.SizeOfOptionalHeader != 0) { + epep->first_section_header_offset += epep->optionalHeader.NumberOfRvaAndSizes * sizeof(EpepImageDataDirectory); + } + return 1; +} + +int epep_get_file_offset_by_rva(Epep *epep, size_t *offset, size_t addr) { + EpepSectionHeader sh = { 0 }; + if (!epep_get_section_header_by_rva(epep, &sh, addr)) { + return 0; + } + size_t diff = addr - sh.VirtualAddress; + if (diff >= sh.SizeOfRawData) { + epep->error_code = EPEP_ERR_ADDRESS_IS_OUT_OF_SECTION_RAW_DATA; + return 0; + } + *offset = sh.PointerToRawData + diff; + return 1; +} + +// +// Data Directories +// + +int epep_get_data_directory_by_index(Epep *epep, EpepImageDataDirectory *idd, size_t index) { + if (index >= epep->optionalHeader.NumberOfRvaAndSizes) { + epep->error_code = EPEP_ERR_DATA_DIRECTORY_INDEX_IS_INVALID; + return 0; + } + size_t offset = epep->first_data_directory_offset + sizeof(EpepImageDataDirectory) * index; + if (!epep_valid_offset(epep, offset, sizeof(EpepImageDataDirectory))) { + epep->error_code = EPEP_ERR_INVALID_DATA_DIRECTORY_OFFSET; + return 0; + } + epep_seek(epep, offset); + idd->VirtualAddress = epep_read_u32(epep); + idd->Size = epep_read_u32(epep); + return 1; +} + +// +// Sections +// + +int epep_get_section_header_by_index(Epep *epep, EpepSectionHeader *sh, size_t index) { + if (index >= epep->coffFileHeader.NumberOfSections) { + epep->error_code = EPEP_ERR_SECTION_HEADER_INDEX_IS_INVALID; + return 0; + } + size_t offset = epep->first_section_header_offset + sizeof(EpepSectionHeader) * index; + if (!epep_valid_offset(epep, offset, sizeof(EpepSectionHeader))) { + epep->error_code = EPEP_ERR_INVALID_SECTION_HEADER_OFFSET; + return 0; + } + epep_seek(epep, offset); + for (int i = 0; i < 8; i++) { + sh->Name[i] = epep_read_u8(epep); + } + sh->VirtualSize = epep_read_u32(epep); + sh->VirtualAddress = epep_read_u32(epep); + sh->SizeOfRawData = epep_read_u32(epep); + sh->PointerToRawData = epep_read_u32(epep); + sh->PointerToRelocations = epep_read_u32(epep); + sh->PointerToLinenumbers = epep_read_u32(epep); + sh->NumberOfRelocations = epep_read_u16(epep); + sh->NumberOfLinenumbers = epep_read_u16(epep); + sh->Characteristics = epep_read_u32(epep); + return 1; +} + +int epep_get_section_header_by_rva(Epep *epep, EpepSectionHeader *sh, size_t addr) { + EpepSectionHeader sh0 = { 0 }; + for (size_t i = 0; i < epep->coffFileHeader.NumberOfSections; i++) { + epep_get_section_header_by_index(epep, &sh0, i); + if (addr >= sh0.VirtualAddress && addr < (sh0.VirtualAddress + sh0.VirtualSize)) { + *sh = sh0; + return 1; + } + } + epep->error_code = EPEP_ERR_ADDRESS_IS_OUT_OF_ANY_SECTION; + return 0; +} + +int epep_get_section_contents(Epep *epep, EpepSectionHeader *sh, void *buf) { + size_t offset = sh->PointerToRawData; + size_t size_of_raw_data = sh->SizeOfRawData; + if (!epep_valid_offset(epep, offset, size_of_raw_data)) { + epep->error_code = EPEP_ERR_INVALID_SECTION_DATA_OFFSET; + return 0; + } + epep_seek(epep, offset); + epep_read_block(epep, size_of_raw_data, buf); + return 1; +} + +// +// COFF Symbols +// + +int epep_get_string_table_size(Epep *epep, size_t *size) { + size_t offset = epep->coffFileHeader.PointerToSymbolTable + 18 * epep->coffFileHeader.NumberOfSymbols; + if (!epep_valid_offset(epep, offset, sizeof(uint32_t))) { + epep->error_code = EPEP_ERR_INVALID_STRING_TABLE_SIZE_OFFSET; + return 0; + } + epep_seek(epep, offset); + *size = epep_read_u32(epep); + return 1; +} + +int epep_get_string_table(Epep *epep, char *string_table) { + size_t size = 0; + if (!epep_get_string_table_size(epep, &size)) { + return 0; + } + // A COFF strings table starts with its size + *string_table++ = (size & 0x000000ff) >> 0; + *string_table++ = (size & 0x0000ff00) >> 8; + *string_table++ = (size & 0x00ff0000) >> 16; + *string_table++ = (size & 0xff000000) >> 24; + epep_read_block(epep, size - 4, string_table); + return 1; +} + +int epep_get_symbol_by_index(Epep *epep, EpepCoffSymbol *sym, size_t index) { + if (epep->kind != EPEP_OBJECT) { + epep->error_code = EPEP_ERR_NOT_AN_OBJECT; + return 0; + } + if (index >= epep->coffFileHeader.NumberOfSymbols) { + epep->error_code = EPEP_ERR_SYMBOL_INDEX_IS_INVALID; + return 0; + } + size_t offset = epep->coffFileHeader.PointerToSymbolTable + 18 * index; + if (!epep_valid_offset(epep, offset, 18)) { + epep->error_code = EPEP_ERR_INVALID_SYMBOL_OFFSET; + return 0; + } + epep_seek(epep, offset); + for (size_t i = 0; i < 18; i++) { + sym->auxFile.FileName[i] = epep_read_u8(epep); + } + return 1; +} + +// +// Imports +// + +int epep_has_import_table(Epep *epep) { + if (epep->kind != EPEP_IMAGE) { + return 0; + } + EpepImageDataDirectory idd = { 0 }; + if (!epep_get_data_directory_by_index(epep, &idd, 1)) { + return 0; + } + return idd.VirtualAddress; +} + +int epep_read_import_table_offset(Epep *epep) { + EpepImageDataDirectory import_table_dd = { 0 }; + if (!epep_get_data_directory_by_index(epep, &import_table_dd, 1)) { + return 0; + } + if (!epep_get_file_offset_by_rva(epep, &epep->import_table_offset, import_table_dd.VirtualAddress)) { + return 0; + } + return 1; +} + +int epep_get_import_directory_by_index(Epep *epep, EpepImportDirectory *import_directory, size_t index) { + if (epep->import_table_offset == 0) { + if (!epep_read_import_table_offset(epep)) { + return 0; + } + } + size_t offset = epep->import_table_offset + index * sizeof(*import_directory); + if (!epep_valid_offset(epep, offset, sizeof(*import_directory))) { + epep->error_code = EPEP_ERR_INVALID_IMPORT_DIRECTORY_OFFSET; + return 0; + } + epep_seek(epep, offset); + epep_read_block(epep, sizeof(*import_directory), import_directory); + return 1; +} + +int epep_get_import_directory_name_s(Epep *epep, EpepImportDirectory *import_directory, char *name, size_t name_max) { + size_t name_rva = import_directory->NameRva; + size_t name_offset = 0; + if (!epep_get_file_offset_by_rva(epep, &name_offset, name_rva)) { + return 0; + } + if (!epep_valid_offset(epep, name_offset, 0)) { + epep->error_code = EPEP_ERR_INVALID_IMPORT_DIRECTORY_NAME_OFFSET; + return 0; + } + epep_seek(epep, name_offset); + epep_read_block(epep, name_max, name); + return 1; +} + +int epep_get_import_directory_lookup_by_index(Epep *epep, EpepImportDirectory *import_directory, size_t *lookup, size_t index) { + size_t first_lookup_offset = 0; + if (!epep_get_file_offset_by_rva(epep, &first_lookup_offset, import_directory->ImportLookupTableRva)) { + return 0; + } + size_t size_of_lookup = is_pe32(epep) ? 4 : 8; + size_t lookup_offset = first_lookup_offset + size_of_lookup * index; + if (!epep_valid_offset(epep, lookup_offset, size_of_lookup)) { + epep->error_code = EPEP_ERR_INVALID_LOOKUP_OFFSET; + return 0; + } + epep_seek(epep, lookup_offset); + epep_read_block(epep, size_of_lookup, lookup); + return 1; +} + +int epep_get_lookup_name_s(Epep *epep, size_t lookup, char *name, size_t name_max) { + if (name_max == 0) { + epep->error_code = EPEP_ERR_OUTPUT_CAPACITY_IS_ZERO; + return 0; + } + if (name == NULL) { + epep->error_code = EPEP_ERR_OUTPUT_IS_NULL; + return 0; + } + uint64_t mask = is_pe32(epep) ? 0x80000000 : 0x8000000000000000; + if (lookup & mask) { + name[0] = '\0'; + return 1; + } + size_t name_rva = lookup; + size_t name_offset = 0; + if (!epep_get_file_offset_by_rva(epep, &name_offset, name_rva)) { + return 0; + } + // skip 2 bytes (Name Table :: Hint) + name_offset += 2; + if (!epep_valid_offset(epep, name_offset, 0)) { + epep->error_code = EPEP_ERR_INVALID_LOOKUP_NAME_OFFSET; + return 0; + } + epep_seek(epep, name_offset); + epep_read_block(epep, name_max, name); + return 1; +} + +// +// Exports +// + +int epep_has_export_table(Epep *epep) { + if (epep->kind != EPEP_IMAGE) { + return 0; + } + EpepImageDataDirectory idd = { 0 }; + if (!epep_get_data_directory_by_index(epep, &idd, 0)) { + return 0; + } + return idd.VirtualAddress; +} + +int epep_read_export_table_offset(Epep *epep) { + EpepImageDataDirectory export_table_dd = { 0 }; + if (!epep_get_data_directory_by_index(epep, &export_table_dd, 0)) { + return 0; + } + if (!epep_get_file_offset_by_rva(epep, &epep->export_table_offset, export_table_dd.VirtualAddress)) { + return 0; + } + return 1; +} + +int epep_read_export_directory(Epep *epep) { + if (epep->export_table_offset == 0) { + if (!epep_read_export_table_offset(epep)) { + return 0; + } + } + if (!epep_valid_offset(epep, epep->export_table_offset, sizeof(epep->export_directory))) { + epep->error_code = EPEP_ERR_INVALID_EXPORT_TABLE_OFFSET; + return 0; + } + epep_seek(epep, epep->export_table_offset); + epep_read_block(epep, sizeof(epep->export_directory), &epep->export_directory); + return 1; +} + +int epep_get_dll_name_s(Epep *epep, char *name, size_t name_max) { + size_t offset = 0; + if (!epep_get_file_offset_by_rva(epep, &offset, epep->export_directory.NameRva)) { + return 0; + } + if (!epep_valid_offset(epep, offset, 0)) { + epep->error_code = EPEP_ERR_INVALID_DLL_NAME_OFFSET; + return 0; + } + epep_seek(epep, offset); + epep_read_block(epep, name_max, name); + return 1; +} + +int epep_get_export_name_pointer_by_index(Epep *epep, size_t *name_rva, size_t index) { + size_t name_pointer_table_rva = epep->export_directory.NamePointerRva; + size_t name_pointer_table_offset = 0; + if (!epep_get_file_offset_by_rva(epep, &name_pointer_table_offset, name_pointer_table_rva)) { + return 0; + } + size_t offset = name_pointer_table_offset + sizeof(uint32_t) * index; + if (!epep_valid_offset(epep, offset, sizeof(uint32_t))) { + epep->error_code = EPEP_ERR_INVALID_EXPORT_NAME_POINTER_OFFSET; + return 0; + } + epep_seek(epep, offset); + *name_rva = epep_read_u32(epep); + return 1; +} + +int epep_get_export_name_s_by_index(Epep *epep, char *name, size_t name_max, size_t index) { + size_t ordinal_table_offset = 0; + if (!epep_get_file_offset_by_rva(epep, &ordinal_table_offset, epep->export_directory.OrdinalTableRva)) { + return 0; + } + if (!epep_valid_offset(epep, ordinal_table_offset, 0)) { + epep->error_code = EPEP_ERR_INVALID_ORDINAL_TABLE_OFFSET; + return 0; + } + epep_seek(epep, ordinal_table_offset); + for (size_t i = 0; i < epep->export_directory.NumberOfNamePointers; i++) { + uint16_t ordinal = epep_read_u16(epep); + if (ordinal == index) { // SPEC_VIOL: Why should not epep->export_directory.OrdinalBase be substracted? + size_t name_rva = 0; + if (!epep_get_export_name_pointer_by_index(epep, &name_rva, i)) { + return 0; + } + size_t name_offset = 0; + if (!epep_get_file_offset_by_rva(epep, &name_offset, name_rva)) { + return 0; + } + if (!epep_valid_offset(epep, name_offset, 0)) { + epep->error_code = EPEP_ERR_INVALID_EXPORT_NAME_OFFSET; + return 0; + } + epep_seek(epep, name_offset); + epep_read_block(epep, name_max, name); + return 1; + } + } + epep->error_code = EPEP_ERR_EXPORT_ADDRESS_TABLE_ENTRY_NAME_NOT_FOUND; + return 0; +} + +int epep_get_export_address_by_index(Epep *epep, EpepExportAddress *export_address, size_t index) { + size_t export_address_table_offset = 0; + if (!epep_get_file_offset_by_rva(epep, &export_address_table_offset, epep->export_directory.ExportAddressTableRva)) { + return 0; + } + EPEP_ASSERT(sizeof(EpepExportAddress) == sizeof(uint32_t)); + size_t offset = export_address_table_offset + sizeof(EpepExportAddress) * index; + if (!epep_valid_offset(epep, offset, sizeof(*export_address))) { + epep->error_code = EPEP_ERR_INVALID_EXPORT_ADDRESS_OFFSET; + return 0; + } + epep_seek(epep, offset); + epep_read_block(epep, sizeof(*export_address), export_address); + return 1; +} + +int epep_get_export_address_forwarder_s(Epep *epep, EpepExportAddress *export_address, char *forwarder, size_t forwarder_max) { + size_t forwarder_offset = 0; + if (!epep_get_file_offset_by_rva(epep, &forwarder_offset, export_address->ForwarderRva)) { + return 0; + } + if (!epep_valid_offset(epep, forwarder_offset, 0)) { + epep->error_code = EPEP_ERR_INVALID_FORWARDER_OFFSET; + return 0; + } + epep_seek(epep, forwarder_offset); + epep_read_block(epep, forwarder_max, forwarder); + return 1; +} + +int epep_export_address_is_forwarder(Epep *epep, EpepExportAddress *export_address) { + EpepImageDataDirectory edd = { 0 }; + if (!epep_get_data_directory_by_index(epep, &edd, 0)) { + return 0; + } + if (export_address->ForwarderRva >= edd.VirtualAddress && export_address->ForwarderRva < edd.VirtualAddress + edd.Size) { + return 1; + } + return 0; +} + +// +// DLL Base Relocaions +// + +int epep_has_base_relocation_table(Epep *epep) { + EpepImageDataDirectory brtdd = { 0 }; + if (!epep_get_data_directory_by_index(epep, &brtdd, 5)) { + return 0; + } + if (brtdd.VirtualAddress == 0) { + return 0; + } + return 1; +} + +int epep_read_base_relocation_table_offset(Epep *epep) { + EpepImageDataDirectory brtdd = { 0 }; + if (!epep_get_data_directory_by_index(epep, &brtdd, 5)) { + return 0; + } + if (!epep_get_file_offset_by_rva(epep, &epep->base_relocation_table_offset, brtdd.VirtualAddress)) { + return 0; + } + epep->base_relocation_table_end_offset = epep->base_relocation_table_offset + brtdd.Size; + return 1; +} + +int epep_get_first_base_relocation_block(Epep *epep, EpepBaseRelocationBlock *brb) { + if (epep->base_relocation_table_offset == 0) { + if (!epep_read_base_relocation_table_offset(epep)) { + return 0; + } + } + if (epep->base_relocation_table_offset == 0) { + epep->error_code = EPEP_ERR_NO_BASE_RELOCATION_TABLE; + return 0; + } + if (!epep_valid_offset(epep, epep->base_relocation_table_offset, 0)) { + epep->error_code = EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_OFFSET; + return 0; + } + if (!epep_seek(epep, epep->base_relocation_table_offset)) { + return 0; + } + brb->offset = epep->base_relocation_table_offset; + brb->PageRva = epep_read_u32(epep); + brb->BlockSize = epep_read_u32(epep); + return 1; +} + +int epep_get_next_base_relocation_block(Epep *epep, EpepBaseRelocationBlock *it) { + if (it->offset == 0) { + epep->error_code = EPEP_ERR_BASE_RELOCATION_IS_ALREADY_END; + return 0; + } + it->offset = it->offset + it->BlockSize; + if (it->offset >= epep->base_relocation_table_end_offset) { + *it = (EpepBaseRelocationBlock){ 0 }; + return 1; + } + if (!epep_valid_offset(epep, it->offset, 0)) { + epep->error_code = EPEP_ERR_INVALID_NEXT_BASE_RELOCATION_BLOCK_OFFSET; + return 0; + } + if (!epep_seek(epep, it->offset)) { + return 0; + } + it->PageRva = epep_read_u32(epep); + it->BlockSize = epep_read_u32(epep); + return 1; +} + +int epep_get_base_relocation_block_base_relocation_by_index(Epep *epep, EpepBaseRelocationBlock *brb, EpepBaseRelocation *br, size_t index) { + size_t offset = brb->offset + 8 + sizeof(EpepBaseRelocation) * index; + if (!epep_valid_offset(epep, offset, sizeof(EpepBaseRelocation))) { + epep->error_code = EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_BASE_RELOCATION_OFFSET; + return 0; + } + if (!epep_seek(epep, offset)) { + return 0; + } + br->u16 = epep_read_u16(epep); + return 1; +} + +// +// COFF Relocations +// + +int epep_get_section_relocation_by_index(Epep *epep, EpepSectionHeader *sh, EpepCoffRelocation *rel, size_t index) { + size_t offset = sh->PointerToRelocations + 10 * index; + if (!epep_valid_offset(epep, offset, 10)) { + epep->error_code = EPEP_ERR_INVALID_SECTION_RELOCATION_OFFSET; + return 0; + } + epep_seek(epep, offset); + epep_read_block(epep, 10, rel); + return 1; +} + +// +// COFF Line Numbers +// + +int epep_get_section_line_number_by_index(Epep *epep, EpepSectionHeader *sh, EpepCoffLinenumber *ln, size_t index) { + size_t offset = sh->PointerToLinenumbers + 6 * index; + if (!epep_valid_offset(epep, offset, 6)) { + epep->error_code = EPEP_ERR_INVALID_LINENUMBER_OFFSET; + return 0; + } + epep_seek(epep, offset); + epep_read_block(epep, 6, ln); + return 1; +} + +#endif // EPEP_INST diff --git a/programs/develop/obj2def/main.c b/programs/develop/obj2def/main.c new file mode 100644 index 0000000000..0ddb864fa1 --- /dev/null +++ b/programs/develop/obj2def/main.c @@ -0,0 +1,265 @@ +#include +#include +#include +#include +#include +#include +#include + +#define EPEP_INST +#include "epep/epep.h" + +const char *epep_errors[] = { + "EPEP_ERR_SUCCESS", + "EPEP_ERR_DATA_DIRECTORY_INDEX_IS_INVALID", + "EPEP_ERR_SECTION_HEADER_INDEX_IS_INVALID", + "EPEP_ERR_SYMBOL_INDEX_IS_INVALID", + "EPEP_ERR_NOT_AN_OBJECT", + "EPEP_ERR_ADDRESS_IS_OUT_OF_SECTION_RAW_DATA", + "EPEP_ERR_OUTPUT_CAPACITY_IS_ZERO", + "EPEP_ERR_OUTPUT_IS_NULL", + "EPEP_ERR_ADDRESS_IS_OUT_OF_ANY_SECTION", + "EPEP_ERR_EXPORT_ADDRESS_TABLE_ENTRY_NAME_NOT_FOUND", + "EPEP_ERR_NO_BASE_RELOCATION_TABLE", + "EPEP_ERR_BASE_RELOCATION_IS_ALREADY_END", + "EPEP_ERR_INVALID_DATA_DIRECTORY_OFFSET", + "EPEP_ERR_INVALID_SECTION_HEADER_OFFSET", + "EPEP_ERR_INVALID_SECTION_DATA_OFFSET", + "EPEP_ERR_INVALID_STRING_TABLE_SIZE_OFFSET", + "EPEP_ERR_INVALID_SYMBOL_OFFSET", + "EPEP_ERR_INVALID_IMPORT_DIRECTORY_OFFSET", + "EPEP_ERR_INVALID_IMPORT_DIRECTORY_NAME_OFFSET", + "EPEP_ERR_INVALID_LOOKUP_OFFSET", + "EPEP_ERR_INVALID_LOOKUP_NAME_OFFSET", + "EPEP_ERR_INVALID_EXPORT_TABLE_OFFSET", + "EPEP_ERR_INVALID_DLL_NAME_OFFSET", + "EPEP_ERR_INVALID_EXPORT_NAME_POINTER_OFFSET", + "EPEP_ERR_INVALID_ORDINAL_TABLE_OFFSET", + "EPEP_ERR_INVALID_EXPORT_NAME_OFFSET", + "EPEP_ERR_INVALID_EXPORT_ADDRESS_OFFSET", + "EPEP_ERR_INVALID_FORWARDER_OFFSET", + "EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_OFFSET", + "EPEP_ERR_INVALID_NEXT_BASE_RELOCATION_BLOCK_OFFSET", + "EPEP_ERR_INVALID_BASE_RELOCATION_BLOCK_BASE_RELOCATION_OFFSET", + "EPEP_ERR_INVALID_SECTION_RELOCATION_OFFSET", + "EPEP_ERR_INVALID_LINENUMBER_OFFSET", +}; + +#define ERROR_EPEP(epep) printf("Error: epep returned %u (%s) at "__FILE__":%u", \ + (epep)->error_code, epep_errors[(epep)->error_code], __LINE__); exit(-1) + +static int emit_logs; +static void log_info(const char *fmt, ...) { + if (emit_logs) { + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + } +} + +uint32_t get32(const char *buf, size_t offset) { + return ((uint32_t)(uint8_t)buf[offset + 0] << 0) + | ((uint32_t)(uint8_t)buf[offset + 1] << 8) + | ((uint32_t)(uint8_t)buf[offset + 2] << 16) + | ((uint32_t)(uint8_t)buf[offset + 3] << 24); +} + +EpepCoffRelocation get_relocation_for_section_and_offset(Epep *epep, EpepSectionHeader *sh, size_t offset) { + EpepCoffRelocation rel = { 0 }; + for (size_t i = 0; i < sh->NumberOfRelocations; i++) { + if (!epep_get_section_relocation_by_index(epep, sh, &rel, i)) { + ERROR_EPEP(epep); + } + if (rel.VirtualAddress == offset) { + return rel; + } + } + printf("Error: Can't find relocation of pointer to name of symbol"); + exit(-1); + return rel; +} + +char *read_string(Epep *epep, size_t section_index, size_t offset) { + EpepSectionHeader sh = { 0 }; + if (!epep_get_section_header_by_index(epep, &sh, section_index)) { + ERROR_EPEP(epep); + } + char *section = calloc(1, sh.SizeOfRawData); + if (!epep_get_section_contents(epep, &sh, section)) { + ERROR_EPEP(epep); + } + char *result = strdup(§ion[offset]); + free(section); + return result; +} + +int gendef(const char *obj_path, const char *outname) { + FILE *out = fopen(outname, "wb"); + Epep epep; + { + FILE *fp = fopen(obj_path, "rb"); + if (!fp) { + printf("Error: Can't open \"%s\"", obj_path); + exit(-1); + } + + if (!epep_init(&epep, fp)) { + ERROR_EPEP(&epep); + } + } + + size_t strtab_size = 0; + if (!epep_get_string_table_size(&epep, &strtab_size)) { + ERROR_EPEP(&epep); + } + + char *strtab = malloc(strtab_size); + if (!epep_get_string_table(&epep, strtab)) { + ERROR_EPEP(&epep); + } + + for (size_t sym_i = 0; sym_i < epep.coffFileHeader.NumberOfSymbols; sym_i++) { + EpepCoffSymbol sym = { 0 }; + + if (!epep_get_symbol_by_index(&epep, &sym, sym_i)) { + ERROR_EPEP(&epep); + } + + size_t name_max = 1024; + char name[name_max]; + + if (sym.symbol.Zeroes == 0) { + strcpy(name, &strtab[sym.symbol.Offset]); + } else { + memcpy(name, sym.symbol.ShortName, 8); + name[8] = '\0'; + } + + if (!strcmp(name, "_EXPORTS") || !strcmp(name, "EXPORTS")) { + fprintf(out, "LIBRARY %s\n\nEXPORTS\n", obj_path); + + size_t export_table_offset_in_section = sym.symbol.Value; + size_t section_index = sym.symbol.SectionNumber - 1; + EpepSectionHeader sh = { 0 }; + if (!epep_get_section_header_by_index(&epep, &sh, section_index)) { + ERROR_EPEP(&epep); + } + size_t section_offset = sh.PointerToRawData; + size_t export_table_offset = section_offset + export_table_offset_in_section; + + char *section = calloc(1, sh.SizeOfRawData); + if (!epep_get_section_contents(&epep, &sh, section)) { + ERROR_EPEP(&epep); + } + + for (size_t offset = export_table_offset_in_section;; offset += 8) { + size_t name_offset = get32(section, offset); + size_t data_offset = get32(section, offset + 4); + + if (name_offset == 0 || data_offset == 0) { + break; + } + + EpepCoffRelocation rel = get_relocation_for_section_and_offset(&epep, &sh, offset); + EpepCoffSymbol name_sym = { 0 }; + if (!epep_get_symbol_by_index(&epep, &name_sym, rel.SymbolTableIndex)) { + ERROR_EPEP(&epep); + } + size_t name_offset_in_section = name_sym.symbol.Value + name_offset; + char *name = read_string(&epep, name_sym.symbol.SectionNumber - 1, name_offset_in_section); + fprintf(out, "%s\n", name); + } + break; + } + sym_i += sym.symbol.NumberOfAuxSymbols; + } +} + +int arg_got_flag(int argc, char **argv, ...) { + char *arg_names[8]; + int arg_name_c = 0; + + va_list ap; + va_start(ap, argv); + for (char *arg_name = va_arg(ap, char *); arg_name; arg_name = va_arg(ap, char *)) { + if (arg_name_c >= 8) { + printf("Internal error: Too many parameter aliases passed to %s", __func__); + exit(-1); + } + arg_names[arg_name_c++] = arg_name; + } + va_end(ap); + + for (int i = 1; i < argc; i++) { + // If an argumetns was handled already then it's NULL here + if (argv[i] == NULL) { + continue; + } + for (int arg_name_i = 0; arg_name_i < arg_name_c; arg_name_i++) { + char *arg_name = arg_names[arg_name_i]; + if (!strcmp(argv[i], arg_name)) { + argv[i] = NULL; // Do not handle this argument as a input name + return i; + } + } + } + return 0; +} + +char *arg_got_param(int argc, char **argv, char *arg) { + int i = arg_got_flag(argc, argv, arg, 0); + if (i == 0) { + return NULL; + } + + if (i + 1 >= argc) { + printf("Warning: %s parameter expects a value (like %s )", arg, arg); + return NULL; + } + char *result = argv[i + 1]; + argv[i + 1] = NULL; + return result; +} + +int usage(char *name, char *remark) { + if (remark) { + printf("Error: %s\n\n", remark); + } + printf("Usage: %s [option]... [object file name]...\n", name); + printf(" Generate DEF files from COFF objects\n"); + printf("\n"); + printf("Options:\n"); + printf(" -v, --verbose Emit information logs\n"); + printf(" -h, --help Output this help and exit\n"); + return 0; +} + +int main(int argc, char **argv) { + if (arg_got_flag(argc, argv, "-h", "-help", "--help", 0)) { + return usage(argv[0], NULL); + } + + emit_logs = arg_got_flag(argc, argv, "-v", "-verbose", "--verbose", 0); + + // After handling arguments there only leaven unhandled ones + // They should be names if inputs. But if there's no input - exit + int input_file_count = 0; + for (int i = 1; i < argc; i++) { + if (argv[i] != NULL) { + input_file_count++; + } + } + if (input_file_count == 0) { + return usage(argv[0], "No input file names supplied"); + } + + for (size_t i = 1; i < argc; i++) { + char outname[256] = { 0 }; + sprintf(outname, "%.*s.def", strlen(argv[i]) - strlen(".obj"), argv[i]); + if (argv[i] != NULL) { + gendef(argv[i], outname); + } + } + return 0; +}