Add unexisted dependencies
git-svn-id: svn://kolibrios.org@8600 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
parent
da8b70d99e
commit
2b98571951
|
@ -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.
|
|
@ -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).
|
|
@ -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_<CVEC_TYPE>_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 <assert.h>
|
||||
// CVEC_MALLOC: Replacement for malloc from <stdlib.h>
|
||||
// CVEC_REALLOC: Replacement for realloc from <stdlib.h>
|
||||
// CVEC_FREE: Replacement for free from <stdlib.h>
|
||||
// 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:
|
||||
// <stddef.h> or another source of size_t and ptrdiff_t
|
||||
// <stdint.h> or another source of SIZE_MAX
|
||||
// <stdlib.h> or another source of malloc, calloc and realloc
|
||||
// <assert.h> 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 <count> 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
|
|
@ -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.
|
|
@ -0,0 +1,24 @@
|
|||
# epep - Embeddable PE Parser
|
||||
## Features
|
||||
|
||||
- PE header (including Data Directories as a part Optional Header)
|
||||
- Section Headers
|
||||
- COFF Symbols
|
||||
- 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"
|
||||
```
|
|
@ -0,0 +1,898 @@
|
|||
// Dependencies:
|
||||
// <assert.h> or any another source of assert()
|
||||
// <stdint.h> or any another source of uint64_t, uint32_t, uint16_t, uint8_t, size_t
|
||||
|
||||
#ifndef EPEP_ASSERT
|
||||
#include <assert.h>
|
||||
#define EPEP_ASSERT(x) assert(x)
|
||||
#endif
|
||||
|
||||
#ifndef EPEP_READER
|
||||
#include <stdio.h>
|
||||
#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_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,
|
||||
} EpepError;
|
||||
|
||||
//
|
||||
// Generic
|
||||
//
|
||||
|
||||
typedef struct {
|
||||
EPEP_READER reader;
|
||||
EpepKind kind;
|
||||
EpepError error_code;
|
||||
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_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);
|
||||
}
|
||||
|
||||
//
|
||||
// Generic
|
||||
//
|
||||
|
||||
int epep_init(Epep *epep, EPEP_READER reader) {
|
||||
*epep = (Epep){ 0 };
|
||||
epep->kind = EPEP_IMAGE;
|
||||
epep->reader = reader;
|
||||
epep->error_code = EPEP_ERR_SUCCESS;
|
||||
epep->signature_offset_offset = 0x3c;
|
||||
epep_seek(epep, epep->signature_offset_offset);
|
||||
epep->signature_offset = 0;
|
||||
epep->signature_offset |= epep_read_u8(epep);
|
||||
epep->signature_offset |= epep_read_u8(epep) << 8;
|
||||
epep->signature_offset |= epep_read_u8(epep) << 16;
|
||||
epep->signature_offset |= epep_read_u8(epep) << 24;
|
||||
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;
|
||||
}
|
||||
epep_seek(epep, epep->first_data_directory_offset + sizeof(EpepImageDataDirectory) * index);
|
||||
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;
|
||||
}
|
||||
epep_seek(epep, epep->first_section_header_offset + sizeof(EpepSectionHeader) * index);
|
||||
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 size_of_raw_data = sh->SizeOfRawData;
|
||||
epep_seek(epep, sh->PointerToRawData);
|
||||
epep_read_block(epep, size_of_raw_data, buf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//
|
||||
// COFF Symbols
|
||||
//
|
||||
|
||||
int epep_get_string_table_size(Epep *epep, size_t *size) {
|
||||
epep_seek(epep, epep->coffFileHeader.PointerToSymbolTable + 18 * epep->coffFileHeader.NumberOfSymbols);
|
||||
*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;
|
||||
}
|
||||
epep_seek(epep, epep->coffFileHeader.PointerToSymbolTable + 18 * index);
|
||||
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;
|
||||
}
|
||||
}
|
||||
epep_seek(epep, epep->import_table_offset + index * sizeof(*import_directory));
|
||||
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;
|
||||
}
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
epep_seek(epep, name_pointer_table_offset + sizeof(uint32_t) * index);
|
||||
*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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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));
|
||||
epep_seek(epep, export_address_table_offset + sizeof(EpepExportAddress) * index);
|
||||
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;
|
||||
}
|
||||
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_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_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) {
|
||||
if (!epep_seek(epep, brb->offset + 8 + sizeof(EpepBaseRelocation) * index)) {
|
||||
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 relocationsOffset = sh->PointerToRelocations;
|
||||
epep_seek(epep, relocationsOffset + 10 * index);
|
||||
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 LinenumbersOffset = sh->PointerToLinenumbers;
|
||||
epep_seek(epep, LinenumbersOffset + 6 * index);
|
||||
epep_read_block(epep, 6, ln);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif // EPEP_INST
|
Loading…
Reference in New Issue