rename all sc_array stuff to vector stuff
This commit is contained in:
@@ -72,19 +72,19 @@ static void file_watch_destroy(int fd, FileWatch *fw) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void file_watch_destroy_watches(FileWatcherContext *ctx) {
|
void file_watch_destroy_watches(FileWatcherContext *ctx) {
|
||||||
for (size_t i = 0; i < sc_array_size(&ctx->watches); i++) {
|
for (size_t i = 0; i < vector_size(&ctx->watches); i++) {
|
||||||
FileWatch *fw = &sc_array_at(&ctx->watches, i);
|
FileWatch *fw = &vector_at(&ctx->watches, i);
|
||||||
file_watch_destroy(ctx->fd, fw);
|
file_watch_destroy(ctx->fd, fw);
|
||||||
}
|
}
|
||||||
sc_array_term(&ctx->watches);
|
vector_term(&ctx->watches);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileWatch *file_watch_find_by_wd(FileWatcherContext *ctx, int wd,
|
FileWatch *file_watch_find_by_wd(FileWatcherContext *ctx, int wd,
|
||||||
size_t *index) {
|
size_t *index) {
|
||||||
struct sc_array_fwatch *watches = &ctx->watches;
|
VectorFileWatch *watches = &ctx->watches;
|
||||||
|
|
||||||
for (size_t i = 0; i < sc_array_size(watches); ++i) {
|
for (size_t i = 0; i < vector_size(watches); ++i) {
|
||||||
FileWatch *fw = &sc_array_at(watches, i);
|
FileWatch *fw = &vector_at(watches, i);
|
||||||
if (fw->wd == wd) {
|
if (fw->wd == wd) {
|
||||||
if (index) {
|
if (index) {
|
||||||
*index = i;
|
*index = i;
|
||||||
@@ -97,8 +97,8 @@ FileWatch *file_watch_find_by_wd(FileWatcherContext *ctx, int wd,
|
|||||||
|
|
||||||
FileWatch *file_watch_find_by_path(FileWatcherContext *ctx, const char *path,
|
FileWatch *file_watch_find_by_path(FileWatcherContext *ctx, const char *path,
|
||||||
size_t *index) {
|
size_t *index) {
|
||||||
for (size_t i = 0; i < sc_array_size(&ctx->watches); i++) {
|
for (size_t i = 0; i < vector_size(&ctx->watches); i++) {
|
||||||
FileWatch *watch = &sc_array_at(&ctx->watches, i);
|
FileWatch *watch = &vector_at(&ctx->watches, i);
|
||||||
if (strcmp(watch->path, path) == 0) {
|
if (strcmp(watch->path, path) == 0) {
|
||||||
if (index) {
|
if (index) {
|
||||||
*index = i;
|
*index = i;
|
||||||
@@ -124,8 +124,8 @@ HiResult file_watch_add(FileWatcherContext *ctx, u32 mask, const char *path) {
|
|||||||
return HI_FAIL;
|
return HI_FAIL;
|
||||||
}
|
}
|
||||||
FileWatch wp = {.wd = wd, .mask = mask, .path = strdup(path)};
|
FileWatch wp = {.wd = wd, .mask = mask, .path = strdup(path)};
|
||||||
sc_array_add(&ctx->watches, wp);
|
vector_add(&ctx->watches, wp);
|
||||||
watch = &sc_array_last(&ctx->watches);
|
watch = &vector_last(&ctx->watches);
|
||||||
} else {
|
} else {
|
||||||
inotify_add_watch(ctx->fd, path, params.file_mask);
|
inotify_add_watch(ctx->fd, path, params.file_mask);
|
||||||
}
|
}
|
||||||
@@ -137,17 +137,17 @@ HiResult file_watch_add(FileWatcherContext *ctx, u32 mask, const char *path) {
|
|||||||
// parent not yet watched
|
// parent not yet watched
|
||||||
int wd = inotify_add_watch(ctx->fd, parent_name, params.parent_mask);
|
int wd = inotify_add_watch(ctx->fd, parent_name, params.parent_mask);
|
||||||
FileWatch wp = {.wd = wd, .mask = HI_FILE_PARENT, .path = parent_name};
|
FileWatch wp = {.wd = wd, .mask = HI_FILE_PARENT, .path = parent_name};
|
||||||
sc_array_init(&wp.files);
|
vector_init(&wp.files);
|
||||||
sc_array_add(&wp.files, watch->path);
|
vector_add(&wp.files, watch->path);
|
||||||
sc_array_add(&ctx->watches, wp);
|
vector_add(&ctx->watches, wp);
|
||||||
} else {
|
} else {
|
||||||
free(parent_name);
|
free(parent_name);
|
||||||
inotify_add_watch(ctx->fd, parent_watch->path, params.parent_mask);
|
inotify_add_watch(ctx->fd, parent_watch->path, params.parent_mask);
|
||||||
{
|
{
|
||||||
// Make sure we don't add a duplicate if the file is already marked
|
// Make sure we don't add a duplicate if the file is already marked
|
||||||
bool exists = false;
|
bool exists = false;
|
||||||
for (size_t i = 0; i < sc_array_size(&parent_watch->files); i++) {
|
for (size_t i = 0; i < vector_size(&parent_watch->files); i++) {
|
||||||
const char *file = sc_array_at(&parent_watch->files, i);
|
const char *file = vector_at(&parent_watch->files, i);
|
||||||
// we store the pointer directly, so this should be fine :D
|
// we store the pointer directly, so this should be fine :D
|
||||||
if (file == watch->path) {
|
if (file == watch->path) {
|
||||||
exists = true;
|
exists = true;
|
||||||
@@ -155,7 +155,7 @@ HiResult file_watch_add(FileWatcherContext *ctx, u32 mask, const char *path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
sc_array_add(&parent_watch->files, watch->path);
|
vector_add(&parent_watch->files, watch->path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,17 +177,17 @@ HiResult file_watch_remove(FileWatcherContext *ctx, const char *path) {
|
|||||||
if (parent_name) {
|
if (parent_name) {
|
||||||
FileWatch *pw = file_watch_find_by_path(ctx, parent_name, NULL);
|
FileWatch *pw = file_watch_find_by_path(ctx, parent_name, NULL);
|
||||||
if (pw) {
|
if (pw) {
|
||||||
for (size_t i = 0; i < sc_array_size(&pw->files); i++) {
|
for (size_t i = 0; i < vector_size(&pw->files); i++) {
|
||||||
const char *fn = sc_array_at(&pw->files, i);
|
const char *fn = vector_at(&pw->files, i);
|
||||||
if (fn == watch->path) {
|
if (fn == watch->path) {
|
||||||
sc_array_del(&pw->files, i);
|
vector_del(&pw->files, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(parent_name);
|
free(parent_name);
|
||||||
}
|
}
|
||||||
file_watch_destroy(ctx->fd, watch);
|
file_watch_destroy(ctx->fd, watch);
|
||||||
sc_array_del(&ctx->watches, i);
|
vector_del(&ctx->watches, i);
|
||||||
return HI_OK;
|
return HI_OK;
|
||||||
}
|
}
|
||||||
return HI_FAIL;
|
return HI_FAIL;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#ifndef FILEWATCH_CONTEXT_H_
|
#ifndef FILEWATCH_CONTEXT_H_
|
||||||
#define FILEWATCH_CONTEXT_H_
|
#define FILEWATCH_CONTEXT_H_
|
||||||
|
|
||||||
#include "vector.h"
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "vector.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents one watch by the user.
|
* Represents one watch by the user.
|
||||||
@@ -16,8 +16,7 @@ typedef struct WatchParams {
|
|||||||
u32 mask;
|
u32 mask;
|
||||||
} WatchParams;
|
} WatchParams;
|
||||||
|
|
||||||
sc_array_def(WatchParams, fwparam);
|
vector_def(WatchParams, WatchParams);
|
||||||
typedef struct sc_array_fwparam VectorWatchParams;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a single watch entity given to inotify.
|
* Represents a single watch entity given to inotify.
|
||||||
@@ -32,8 +31,7 @@ typedef struct FileWatch {
|
|||||||
VectorStr files;
|
VectorStr files;
|
||||||
} FileWatch;
|
} FileWatch;
|
||||||
|
|
||||||
sc_array_def(FileWatch, fwatch);
|
vector_def(FileWatch, FileWatch);
|
||||||
typedef struct sc_array_fwatch VectorFileWatch;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the required data to understand a running FileWatcher.
|
* Holds the required data to understand a running FileWatcher.
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
#include "filewatch_context.h"
|
#include "filewatch_context.h"
|
||||||
#include "filewatch_type.h"
|
#include "filewatch_type.h"
|
||||||
|
|
||||||
#include "vector.h"
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "vector.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
@@ -19,8 +19,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
sc_array_def(FileEvent, fwevent);
|
vector_def(FileEvent, FileEvent);
|
||||||
typedef struct sc_array_fwevent VectorFileEvent;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All context and state required to run a file watcher.
|
* All context and state required to run a file watcher.
|
||||||
@@ -34,7 +33,6 @@ typedef struct FileWatcher {
|
|||||||
VectorFileEvent events;
|
VectorFileEvent events;
|
||||||
} FileWatcher;
|
} FileWatcher;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Watch Params
|
* Watch Params
|
||||||
*/
|
*/
|
||||||
@@ -50,8 +48,8 @@ static WatchParams *watch_params_find_by_path(const char *path,
|
|||||||
FileWatcherContext *ctx,
|
FileWatcherContext *ctx,
|
||||||
size_t *index) {
|
size_t *index) {
|
||||||
const VectorWatchParams *params = &ctx->params;
|
const VectorWatchParams *params = &ctx->params;
|
||||||
for (size_t i = 0; i < sc_array_size(params); ++i) {
|
for (size_t i = 0; i < vector_size(params); ++i) {
|
||||||
WatchParams *param = &sc_array_at(params, i);
|
WatchParams *param = &vector_at(params, i);
|
||||||
if (strcmp(path, param->path) == 0) {
|
if (strcmp(path, param->path) == 0) {
|
||||||
if (index)
|
if (index)
|
||||||
*index = i;
|
*index = i;
|
||||||
@@ -68,7 +66,7 @@ static WatchParams *watch_params_find_by_path(const char *path,
|
|||||||
#define NULL_EVENT (FileEvent){0};
|
#define NULL_EVENT (FileEvent){0};
|
||||||
|
|
||||||
static FileEvent file_event_create(const struct inotify_event *inevent,
|
static FileEvent file_event_create(const struct inotify_event *inevent,
|
||||||
FileWatcherContext *ctx) {
|
FileWatcherContext *ctx) {
|
||||||
FileEvent event = {0};
|
FileEvent event = {0};
|
||||||
|
|
||||||
if (!inevent) {
|
if (!inevent) {
|
||||||
@@ -101,8 +99,8 @@ static FileEvent file_event_create(const struct inotify_event *inevent,
|
|||||||
filename[fullpath_size] = '\0';
|
filename[fullpath_size] = '\0';
|
||||||
|
|
||||||
// find if file is associated with any path
|
// find if file is associated with any path
|
||||||
for (size_t i = 0; i < sc_array_size(&fw->files); ++i) {
|
for (size_t i = 0; i < vector_size(&fw->files); ++i) {
|
||||||
const char *watched_file = sc_array_at(&fw->files, i);
|
const char *watched_file = vector_at(&fw->files, i);
|
||||||
if (strcmp(watched_file, filename) == 0) {
|
if (strcmp(watched_file, filename) == 0) {
|
||||||
|
|
||||||
// check if event mask matches the watcher mask
|
// check if event mask matches the watcher mask
|
||||||
@@ -147,9 +145,9 @@ FileEvent file_event_pop(FileWatcher *fw) {
|
|||||||
mtx_lock(&fw->mutex);
|
mtx_lock(&fw->mutex);
|
||||||
|
|
||||||
FileEvent e = NULL_EVENT;
|
FileEvent e = NULL_EVENT;
|
||||||
if (sc_array_size(&fw->events) > 0) {
|
if (vector_size(&fw->events) > 0) {
|
||||||
e = sc_array_last(&fw->events);
|
e = vector_last(&fw->events);
|
||||||
sc_array_del_last(&fw->events);
|
vector_del_last(&fw->events);
|
||||||
}
|
}
|
||||||
|
|
||||||
mtx_unlock(&fw->mutex);
|
mtx_unlock(&fw->mutex);
|
||||||
@@ -167,8 +165,8 @@ static HiResult file_watcher_ctx_init(FileWatcherContext *ctx) {
|
|||||||
return HI_FAIL;
|
return HI_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
sc_array_init(&ctx->watches);
|
vector_init(&ctx->watches);
|
||||||
sc_array_init(&ctx->params);
|
vector_init(&ctx->params);
|
||||||
return HI_OK;
|
return HI_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +194,7 @@ FileWatcher *file_watcher_create() {
|
|||||||
free(fw);
|
free(fw);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
sc_array_init(&fw->events);
|
vector_init(&fw->events);
|
||||||
mtx_init(&fw->mutex, mtx_plain);
|
mtx_init(&fw->mutex, mtx_plain);
|
||||||
cnd_init(&fw->cond);
|
cnd_init(&fw->cond);
|
||||||
fw->running = true;
|
fw->running = true;
|
||||||
@@ -226,7 +224,7 @@ HiResult file_watcher_add(FileWatcher *fw, const char *filename, u32 flags) {
|
|||||||
watch_params_find_by_path(filename, &fw->context, NULL);
|
watch_params_find_by_path(filename, &fw->context, NULL);
|
||||||
if (!params) {
|
if (!params) {
|
||||||
WatchParams params = watch_params_create(filename, flags);
|
WatchParams params = watch_params_create(filename, flags);
|
||||||
sc_array_add(&fw->context.params, params);
|
vector_add(&fw->context.params, params);
|
||||||
} else {
|
} else {
|
||||||
params->mask |= flags;
|
params->mask |= flags;
|
||||||
}
|
}
|
||||||
@@ -252,7 +250,7 @@ HiResult hi_file_watcher_remove(FileWatcher *fw, const char *filename) {
|
|||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
WatchParams *params = watch_params_find_by_path(filename, &fw->context, &i);
|
WatchParams *params = watch_params_find_by_path(filename, &fw->context, &i);
|
||||||
watch_params_destroy(params);
|
watch_params_destroy(params);
|
||||||
sc_array_del(&fw->context.params, i);
|
vector_del(&fw->context.params, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
mtx_unlock(&fw->mutex);
|
mtx_unlock(&fw->mutex);
|
||||||
@@ -306,11 +304,11 @@ int file_watcher_watch(void *arg) {
|
|||||||
event = (const struct inotify_event *)ptr;
|
event = (const struct inotify_event *)ptr;
|
||||||
FileEvent e = file_event_create(event, &ctx->context);
|
FileEvent e = file_event_create(event, &ctx->context);
|
||||||
if (e.type != HI_FILE_NONE) {
|
if (e.type != HI_FILE_NONE) {
|
||||||
sc_array_add(&ctx->events, e);
|
vector_add(&ctx->events, e);
|
||||||
|
|
||||||
if (event->len) {
|
if (event->len) {
|
||||||
sc_log_debug("Event created: queue-size: %u, %s %s\n",
|
sc_log_debug("Event created: queue-size: %u, %s %s\n",
|
||||||
sc_array_size(&ctx->events), e.pathname,
|
vector_size(&ctx->events), e.pathname,
|
||||||
hi_file_watch_type_to_str(e.type));
|
hi_file_watch_type_to_str(e.type));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
49
src/hiload.c
49
src/hiload.c
@@ -1,13 +1,13 @@
|
|||||||
#include "hiload/hiload.h"
|
#include "hiload/hiload.h"
|
||||||
|
|
||||||
#include "vector.h"
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "filewatcher/filewatcher.h"
|
#include "filewatcher/filewatcher.h"
|
||||||
|
#include "histring.h"
|
||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "memmap.h"
|
#include "memmap.h"
|
||||||
#include "moduler.h"
|
#include "moduler.h"
|
||||||
#include "histring.h"
|
|
||||||
#include "symbols.h"
|
#include "symbols.h"
|
||||||
|
#include "vector.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
@@ -27,7 +27,6 @@ static const char *module_exclude_filter[] = {
|
|||||||
"/usr/", "/lib/", "/lib64/", "/bin/", "/opt/",
|
"/usr/", "/lib/", "/lib64/", "/bin/", "/opt/",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
VectorMemoryMap memory_regions;
|
VectorMemoryMap memory_regions;
|
||||||
VectorStr enabled_modules;
|
VectorStr enabled_modules;
|
||||||
@@ -71,7 +70,7 @@ static int gather_module_data_callback(struct dl_phdr_info *info, size_t size,
|
|||||||
// Mark everything but system and virtual modules as patchable
|
// Mark everything but system and virtual modules as patchable
|
||||||
if (module.name[0] == '/') {
|
if (module.name[0] == '/') {
|
||||||
if (!hi_str_starts_with(module.name, ARRLEN(module_exclude_filter),
|
if (!hi_str_starts_with(module.name, ARRLEN(module_exclude_filter),
|
||||||
module_exclude_filter)) {
|
module_exclude_filter)) {
|
||||||
module.info = hi_modinfo_add(module.info, HI_MODULE_STATE_PATCHABLE);
|
module.info = hi_modinfo_add(module.info, HI_MODULE_STATE_PATCHABLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,17 +78,17 @@ static int gather_module_data_callback(struct dl_phdr_info *info, size_t size,
|
|||||||
log_debugv("dli_fname: %s\n", dl_info.dli_fname);
|
log_debugv("dli_fname: %s\n", dl_info.dli_fname);
|
||||||
log_debugv("dli_sname: %s\n", dl_info.dli_sname);
|
log_debugv("dli_sname: %s\n", dl_info.dli_sname);
|
||||||
|
|
||||||
for (size_t i = 0; i < sc_array_size(&context.enabled_modules); i++) {
|
for (size_t i = 0; i < vector_size(&context.enabled_modules); i++) {
|
||||||
|
|
||||||
// If module is in the provided modules list
|
// If module is in the provided modules list
|
||||||
if (hi_path_has_filename(modname,
|
if (hi_path_has_filename(modname,
|
||||||
sc_array_at(&context.enabled_modules, i))) {
|
vector_at(&context.enabled_modules, i))) {
|
||||||
|
|
||||||
// Replace shortform with str pointer from module info
|
// Replace shortform with str pointer from module info
|
||||||
sc_array_at(&context.enabled_modules, i) = module.name;
|
vector_at(&context.enabled_modules, i) = module.name;
|
||||||
|
|
||||||
if (!HIOK(file_watcher_add(context.filewatcher, modpath,
|
if (!HIOK(file_watcher_add(context.filewatcher, modpath,
|
||||||
HI_FILE_ALL_EVENTS))) {
|
HI_FILE_ALL_EVENTS))) {
|
||||||
log_error("Failed to set filewatcher for: '%s'\n", modpath);
|
log_error("Failed to set filewatcher for: '%s'\n", modpath);
|
||||||
} else {
|
} else {
|
||||||
log_info("Watching file: %s\n", modpath);
|
log_info("Watching file: %s\n", modpath);
|
||||||
@@ -102,7 +101,7 @@ static int gather_module_data_callback(struct dl_phdr_info *info, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
VectorModuleData *modules = (VectorModuleData *)data;
|
VectorModuleData *modules = (VectorModuleData *)data;
|
||||||
sc_array_add(modules, module);
|
vector_add(modules, module);
|
||||||
|
|
||||||
return 0; // Continue iteration
|
return 0; // Continue iteration
|
||||||
}
|
}
|
||||||
@@ -111,14 +110,14 @@ static void module_infos_free(VectorModuleData *modules) {
|
|||||||
if (!modules)
|
if (!modules)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (size_t i = 0; i < sc_array_size(modules); i++) {
|
for (size_t i = 0; i < vector_size(modules); i++) {
|
||||||
free((char *)sc_array_at(modules, i).name);
|
free((char *)vector_at(modules, i).name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HiResult gather_module_infos(VectorModuleData *modules) {
|
static HiResult gather_module_infos(VectorModuleData *modules) {
|
||||||
|
|
||||||
sc_array_init(modules);
|
vector_init(modules);
|
||||||
|
|
||||||
// Iterate over all loaded shared objects
|
// Iterate over all loaded shared objects
|
||||||
if (dl_iterate_phdr(gather_module_data_callback, modules) != 0) {
|
if (dl_iterate_phdr(gather_module_data_callback, modules) != 0) {
|
||||||
@@ -131,10 +130,10 @@ HiResult gather_module_infos(VectorModuleData *modules) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ModuleData *get_module_by_path(const char *path,
|
static ModuleData *get_module_by_path(const char *path,
|
||||||
VectorModuleData *modules) {
|
VectorModuleData *modules) {
|
||||||
|
|
||||||
for (size_t i = 0; i < sc_array_size(modules); i++) {
|
for (size_t i = 0; i < vector_size(modules); i++) {
|
||||||
ModuleData *module = &sc_array_at(modules, i);
|
ModuleData *module = &vector_at(modules, i);
|
||||||
const char *name = module->name;
|
const char *name = module->name;
|
||||||
if (strcmp(name, path) == 0) {
|
if (strcmp(name, path) == 0) {
|
||||||
return module;
|
return module;
|
||||||
@@ -166,11 +165,11 @@ static void handle_events(FileWatcher *fw, VectorModuleData *modules) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *find_string_from_array(const char *needle,
|
static const char *find_string_from_array(const char *needle,
|
||||||
const struct sc_array_str *haystack) {
|
const VectorStr *haystack) {
|
||||||
|
|
||||||
for (size_t i = 0; i < sc_array_size(haystack); i++) {
|
for (size_t i = 0; i < vector_size(haystack); i++) {
|
||||||
if (strcmp(needle, sc_array_at(haystack, i)) == 0) {
|
if (strcmp(needle, vector_at(haystack, i)) == 0) {
|
||||||
return sc_array_at(haystack, i);
|
return vector_at(haystack, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,8 +179,8 @@ static const char *find_string_from_array(const char *needle,
|
|||||||
static HiResult reload_dirty_modules(HiloadContext *context) {
|
static HiResult reload_dirty_modules(HiloadContext *context) {
|
||||||
|
|
||||||
HiResult ret = HI_OK;
|
HiResult ret = HI_OK;
|
||||||
for (u8 i = 0; i < sc_array_size(&context->modules); i++) {
|
for (u8 i = 0; i < vector_size(&context->modules); i++) {
|
||||||
ModuleData *module = &sc_array_at(&context->modules, i);
|
ModuleData *module = &vector_at(&context->modules, i);
|
||||||
|
|
||||||
// Operate on dirty modules only
|
// Operate on dirty modules only
|
||||||
if (hi_modinfo_has(module->info, HI_MODULE_STATE_DIRTY)) {
|
if (hi_modinfo_has(module->info, HI_MODULE_STATE_DIRTY)) {
|
||||||
@@ -203,8 +202,6 @@ static HiResult reload_dirty_modules(HiloadContext *context) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int hi_init(size_t n, const char **enabled_modules) {
|
int hi_init(size_t n, const char **enabled_modules) {
|
||||||
|
|
||||||
if (log_init() != 0) {
|
if (log_init() != 0) {
|
||||||
@@ -220,10 +217,10 @@ int hi_init(size_t n, const char **enabled_modules) {
|
|||||||
for (unsigned i = 0; i < n; i++) {
|
for (unsigned i = 0; i < n; i++) {
|
||||||
const char *module_name = enabled_modules[i];
|
const char *module_name = enabled_modules[i];
|
||||||
log_info("Enabling module: '%s'\n", module_name);
|
log_info("Enabling module: '%s'\n", module_name);
|
||||||
sc_array_add(&context.enabled_modules, module_name);
|
vector_add(&context.enabled_modules, module_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
sc_array_init(&context.memory_regions);
|
vector_init(&context.memory_regions);
|
||||||
if (memmaps_from_process(&context.memory_regions) != HI_OK) {
|
if (memmaps_from_process(&context.memory_regions) != HI_OK) {
|
||||||
log_error("Could not populate program memory maps.\n");
|
log_error("Could not populate program memory maps.\n");
|
||||||
return HI_FAIL;
|
return HI_FAIL;
|
||||||
|
|||||||
22
src/memmap.c
22
src/memmap.c
@@ -10,7 +10,7 @@ static inline int ptr_in_range(uptr ptr, uptr start, uptr end) {
|
|||||||
|
|
||||||
HiResult memmaps_find_by_ptr(uptr ptr, VectorMemoryMap *const maps,
|
HiResult memmaps_find_by_ptr(uptr ptr, VectorMemoryMap *const maps,
|
||||||
size_t *index) {
|
size_t *index) {
|
||||||
for (size_t i = 0; i < sc_array_size(maps); i++) {
|
for (size_t i = 0; i < vector_size(maps); i++) {
|
||||||
uptr start = maps->elems[i].span.start;
|
uptr start = maps->elems[i].span.start;
|
||||||
// we assume a sorted region by start address, so we can do a quick discard
|
// we assume a sorted region by start address, so we can do a quick discard
|
||||||
if (ptr < start)
|
if (ptr < start)
|
||||||
@@ -71,7 +71,7 @@ HiResult memmaps_from_process(VectorMemoryMap *outmaps) {
|
|||||||
reg.pathname = strdup(pathname);
|
reg.pathname = strdup(pathname);
|
||||||
}
|
}
|
||||||
|
|
||||||
sc_array_add(outmaps, reg);
|
vector_add(outmaps, reg);
|
||||||
line = strtok(NULL, "\n");
|
line = strtok(NULL, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,12 +80,12 @@ HiResult memmaps_from_process(VectorMemoryMap *outmaps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MemorySpan memmaps_find_by_name(const char region_name[static 1],
|
MemorySpan memmaps_find_by_name(const char region_name[static 1],
|
||||||
const VectorMemoryMap *const maps) {
|
const VectorMemoryMap *const maps) {
|
||||||
uptr start = ~0ull;
|
uptr start = ~0ull;
|
||||||
uptr end = 0;
|
uptr end = 0;
|
||||||
for (size_t i = 0; i < sc_array_size(maps); i++) {
|
for (size_t i = 0; i < vector_size(maps); i++) {
|
||||||
|
|
||||||
const MemoryMap *reg = &sc_array_at(maps, i);
|
const MemoryMap *reg = &vector_at(maps, i);
|
||||||
|
|
||||||
if (reg->pathname && strcmp(reg->pathname, region_name) == 0) {
|
if (reg->pathname && strcmp(reg->pathname, region_name) == 0) {
|
||||||
if (reg->span.start < start) {
|
if (reg->span.start < start) {
|
||||||
@@ -106,17 +106,17 @@ MemorySpan memmaps_find_by_name(const char region_name[static 1],
|
|||||||
}
|
}
|
||||||
|
|
||||||
void memmaps_clear(VectorMemoryMap *maps) {
|
void memmaps_clear(VectorMemoryMap *maps) {
|
||||||
for (size_t i = 0; i < sc_array_size(maps); i++) {
|
for (size_t i = 0; i < vector_size(maps); i++) {
|
||||||
memmap_free(&sc_array_at(maps, i));
|
memmap_free(&vector_at(maps, i));
|
||||||
}
|
}
|
||||||
sc_array_clear(maps);
|
vector_clear(maps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void memmaps_term(VectorMemoryMap *maps) {
|
void memmaps_term(VectorMemoryMap *maps) {
|
||||||
for (size_t i = 0; i < sc_array_size(maps); i++) {
|
for (size_t i = 0; i < vector_size(maps); i++) {
|
||||||
memmap_free(&sc_array_at(maps, i));
|
memmap_free(&vector_at(maps, i));
|
||||||
}
|
}
|
||||||
sc_array_term(maps);
|
vector_term(maps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void memmap_free(MemoryMap *reg) {
|
void memmap_free(MemoryMap *reg) {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ typedef struct MemorySpan {
|
|||||||
*/
|
*/
|
||||||
typedef struct MemoryMap {
|
typedef struct MemoryMap {
|
||||||
/**
|
/**
|
||||||
* Might be null as not all regions have a name or a path.
|
* Might be null as not all regions have a name or a path. Owning if not null.
|
||||||
*/
|
*/
|
||||||
const char *pathname;
|
const char *pathname;
|
||||||
MemorySpan span;
|
MemorySpan span;
|
||||||
@@ -37,8 +37,7 @@ typedef struct MemoryMap {
|
|||||||
u32 permissions; // enum MemoryPermissions
|
u32 permissions; // enum MemoryPermissions
|
||||||
} MemoryMap;
|
} MemoryMap;
|
||||||
|
|
||||||
sc_array_def(MemoryMap, memmap);
|
vector_def(MemoryMap, MemoryMap);
|
||||||
typedef struct sc_array_memmap VectorMemoryMap;
|
|
||||||
|
|
||||||
/// Free memory and zero maps
|
/// Free memory and zero maps
|
||||||
void memmaps_term(VectorMemoryMap *maps);
|
void memmaps_term(VectorMemoryMap *maps);
|
||||||
@@ -84,4 +83,4 @@ HiResult memmaps_find_by_ptr(uptr ptr, VectorMemoryMap *const maps,
|
|||||||
* @param maps The haystack
|
* @param maps The haystack
|
||||||
*/
|
*/
|
||||||
MemorySpan memmaps_find_by_name(const char region_name[static 1],
|
MemorySpan memmaps_find_by_name(const char region_name[static 1],
|
||||||
const VectorMemoryMap *const maps);
|
const VectorMemoryMap *const maps);
|
||||||
|
|||||||
@@ -33,10 +33,10 @@ static void *adjust_if_relative(void *ptr, void *module_base) {
|
|||||||
return (void *)p;
|
return (void *)p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static HiResult gather_patchable_symbols(struct sc_array_sym *symbols,
|
static HiResult gather_patchable_symbols(VectorSymbol *symbols,
|
||||||
const char *module_name,
|
const char *module_name,
|
||||||
void *module_base) {
|
void *module_base) {
|
||||||
sc_array_clear(symbols);
|
symbol_clear(symbols);
|
||||||
|
|
||||||
HiResult ret = HI_FAIL;
|
HiResult ret = HI_FAIL;
|
||||||
|
|
||||||
@@ -152,7 +152,7 @@ static HiResult gather_patchable_symbols(struct sc_array_sym *symbols,
|
|||||||
.type = type,
|
.type = type,
|
||||||
.address = sym_addr};
|
.address = sym_addr};
|
||||||
|
|
||||||
sc_array_add(symbols, hisym);
|
vector_add(symbols, hisym);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -226,7 +226,7 @@ static HiResult moduler_apply_module_patch(VectorSymbol *psymbols,
|
|||||||
|
|
||||||
printf("Processing %zu relocations\n", rela_count);
|
printf("Processing %zu relocations\n", rela_count);
|
||||||
|
|
||||||
size_t num_symbols = sc_array_size(psymbols);
|
size_t num_symbols = vector_size(psymbols);
|
||||||
ElfW(Rela) *r = NULL;
|
ElfW(Rela) *r = NULL;
|
||||||
for (size_t i = 0; i < rela_count; i++) {
|
for (size_t i = 0; i < rela_count; i++) {
|
||||||
|
|
||||||
@@ -247,7 +247,7 @@ static HiResult moduler_apply_module_patch(VectorSymbol *psymbols,
|
|||||||
|
|
||||||
// Check if this is a symbol we want to patch
|
// Check if this is a symbol we want to patch
|
||||||
for (size_t j = 0; j < num_symbols; j++) {
|
for (size_t j = 0; j < num_symbols; j++) {
|
||||||
Symbol *sym = &sc_array_at(psymbols, j);
|
Symbol *sym = &vector_at(psymbols, j);
|
||||||
if (strcmp(sym->name, name) == 0) {
|
if (strcmp(sym->name, name) == 0) {
|
||||||
sym->got_entry = got_entry;
|
sym->got_entry = got_entry;
|
||||||
sym->orig_address = *got_entry; // Save the original function
|
sym->orig_address = *got_entry; // Save the original function
|
||||||
@@ -260,7 +260,6 @@ static HiResult moduler_apply_module_patch(VectorSymbol *psymbols,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
elf_end(elf);
|
elf_end(elf);
|
||||||
return HI_OK;
|
return HI_OK;
|
||||||
}
|
}
|
||||||
@@ -324,13 +323,16 @@ HiResult moduler_reload(VectorModuleData *modules, ModuleData *module,
|
|||||||
patch.dlhandle = new_handle;
|
patch.dlhandle = new_handle;
|
||||||
|
|
||||||
// refresh cache
|
// refresh cache
|
||||||
memmaps_from_process(memmaps);
|
if (!HIOK(memmaps_from_process(memmaps))) {
|
||||||
|
log_error("Failed to collect memory information for process\n");
|
||||||
|
return HI_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
patch.memreg = memmaps_find_by_name(patch.filename, memmaps);
|
patch.memreg = memmaps_find_by_name(patch.filename, memmaps);
|
||||||
void *patch_base = (void *)patch.memreg.start;
|
void *patch_base = (void *)patch.memreg.start;
|
||||||
|
|
||||||
VectorSymbol patch_symbols;
|
VectorSymbol patch_symbols;
|
||||||
symbol_init_symbols(&patch_symbols);
|
symbol_init(&patch_symbols);
|
||||||
|
|
||||||
HiResult ret =
|
HiResult ret =
|
||||||
gather_patchable_symbols(&patch_symbols, patch.filename, patch_base);
|
gather_patchable_symbols(&patch_symbols, patch.filename, patch_base);
|
||||||
@@ -339,8 +341,8 @@ HiResult moduler_reload(VectorModuleData *modules, ModuleData *module,
|
|||||||
return HI_FAIL;
|
return HI_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < sc_array_size(modules); ++i) {
|
for (size_t i = 0; i < vector_size(modules); ++i) {
|
||||||
ModuleData mod = sc_array_at(modules, i);
|
ModuleData mod = vector_at(modules, i);
|
||||||
|
|
||||||
if (!hi_modinfo_has(mod.info, HI_MODULE_STATE_PATCHABLE))
|
if (!hi_modinfo_has(mod.info, HI_MODULE_STATE_PATCHABLE))
|
||||||
continue;
|
continue;
|
||||||
@@ -354,18 +356,18 @@ HiResult moduler_reload(VectorModuleData *modules, ModuleData *module,
|
|||||||
// coping those over.
|
// coping those over.
|
||||||
|
|
||||||
VectorSymbol module_symbols;
|
VectorSymbol module_symbols;
|
||||||
symbol_init_symbols(&module_symbols);
|
symbol_init(&module_symbols);
|
||||||
ret = gather_patchable_symbols(&module_symbols, mod.name,
|
ret = gather_patchable_symbols(&module_symbols, mod.name,
|
||||||
(void *)mod.address);
|
(void *)mod.address);
|
||||||
if (!HIOK(ret)) {
|
if (!HIOK(ret)) {
|
||||||
log_error("Failed to gather symbols for %s\n", mod.name);
|
log_error("Failed to gather symbols for %s\n", mod.name);
|
||||||
symbol_term_symbols(&module_symbols);
|
symbol_term(&module_symbols);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy old data to new data. Breaks with layout changes.
|
// Copy old data to new data. Breaks with layout changes.
|
||||||
for (size_t i = 0; i < sc_array_size(&module_symbols); ++i) {
|
for (size_t i = 0; i < vector_size(&module_symbols); ++i) {
|
||||||
Symbol *sym = &sc_array_at(&module_symbols, i);
|
Symbol *sym = &vector_at(&module_symbols, i);
|
||||||
if (sym->type == HI_SYMBOL_TYPE_OBJECT) {
|
if (sym->type == HI_SYMBOL_TYPE_OBJECT) {
|
||||||
Symbol *ps = symbol_find(&patch_symbols, sym);
|
Symbol *ps = symbol_find(&patch_symbols, sym);
|
||||||
if (ps) {
|
if (ps) {
|
||||||
@@ -378,14 +380,14 @@ HiResult moduler_reload(VectorModuleData *modules, ModuleData *module,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
symbol_term_symbols(&module_symbols);
|
symbol_term(&module_symbols);
|
||||||
}
|
}
|
||||||
|
|
||||||
module->info = hi_modinfo_clear(module->info, HI_MODULE_STATE_DIRTY);
|
module->info = hi_modinfo_clear(module->info, HI_MODULE_STATE_DIRTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
free((char *)patch.filename);
|
free((char *)patch.filename);
|
||||||
symbol_term_symbols(&patch_symbols);
|
symbol_term(&patch_symbols);
|
||||||
|
|
||||||
dlclose(module->dlhandle);
|
dlclose(module->dlhandle);
|
||||||
module->dlhandle = patch.dlhandle;
|
module->dlhandle = patch.dlhandle;
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "vector.h"
|
|
||||||
#include "memmap.h"
|
#include "memmap.h"
|
||||||
#include "symbols.h"
|
#include "symbols.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "vector.h"
|
||||||
|
|
||||||
struct HiloadContext;
|
struct HiloadContext;
|
||||||
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
HI_MODULE_STATE_DIRTY = (1 << 0),
|
HI_MODULE_STATE_DIRTY = (1 << 0),
|
||||||
HI_MODULE_STATE_PATCHABLE = (1 << 6), // non system module we will modify
|
HI_MODULE_STATE_PATCHABLE = (1 << 6), // non system module we will modify
|
||||||
@@ -22,14 +21,12 @@ typedef struct {
|
|||||||
ModuleInfo info;
|
ModuleInfo info;
|
||||||
} ModuleData;
|
} ModuleData;
|
||||||
|
|
||||||
sc_array_def(ModuleData, module);
|
vector_def(ModuleData, ModuleData);
|
||||||
typedef struct sc_array_module VectorModuleData;
|
|
||||||
|
|
||||||
static inline ModuleInfo hi_modinfo_add(ModuleInfo flags, ModuleFlags flag) {
|
static inline ModuleInfo hi_modinfo_add(ModuleInfo flags, ModuleFlags flag) {
|
||||||
return flags | flag;
|
return flags | flag;
|
||||||
}
|
}
|
||||||
static inline ModuleInfo hi_modinfo_clear(ModuleInfo flags,
|
static inline ModuleInfo hi_modinfo_clear(ModuleInfo flags, ModuleFlags flag) {
|
||||||
ModuleFlags flag) {
|
|
||||||
return flags & ~flag;
|
return flags & ~flag;
|
||||||
}
|
}
|
||||||
static inline bool hi_modinfo_has(ModuleInfo flags, ModuleFlags flag) {
|
static inline bool hi_modinfo_has(ModuleInfo flags, ModuleFlags flag) {
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
Symbol *symbol_find(VectorSymbol *symbols, Symbol *symbol) {
|
Symbol *symbol_find(VectorSymbol *symbols, Symbol *symbol) {
|
||||||
for (size_t i=0; i < sc_array_size(symbols); ++i) {
|
for (size_t i = 0; i < vector_size(symbols); ++i) {
|
||||||
Symbol *s = &sc_array_at(symbols, i);
|
Symbol *s = &vector_at(symbols, i);
|
||||||
if (strcmp(s->name, symbol->name) == 0) {
|
if (strcmp(s->name, symbol->name) == 0) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "vector.h"
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include "vector.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
HI_SYMBOL_BIND_LOCAL,
|
HI_SYMBOL_BIND_LOCAL,
|
||||||
@@ -19,8 +19,7 @@ typedef enum {
|
|||||||
HI_SYMBOL_TYPE_TLS,
|
HI_SYMBOL_TYPE_TLS,
|
||||||
} SymbolType;
|
} SymbolType;
|
||||||
|
|
||||||
typedef struct Symbol Symbol;
|
typedef struct Symbol {
|
||||||
struct Symbol {
|
|
||||||
const char *name;
|
const char *name;
|
||||||
SymbolBind binding;
|
SymbolBind binding;
|
||||||
SymbolType type;
|
SymbolType type;
|
||||||
@@ -28,30 +27,30 @@ struct Symbol {
|
|||||||
void *address;
|
void *address;
|
||||||
void **got_entry;
|
void **got_entry;
|
||||||
void *orig_address;
|
void *orig_address;
|
||||||
};
|
} Symbol;
|
||||||
|
|
||||||
sc_array_def(Symbol, sym);
|
vector_def(Symbol, Symbol);
|
||||||
typedef struct sc_array_sym VectorSymbol;
|
|
||||||
|
|
||||||
static inline void symbol_free(Symbol *symbol) { free((char *)symbol->name); }
|
static inline void symbol_free(Symbol *symbol) { free((char *)symbol->name); }
|
||||||
|
|
||||||
static inline void symbol_init_symbols(VectorSymbol *symbols) {
|
static inline void symbol_init(VectorSymbol *symbols) { vector_init(symbols); }
|
||||||
sc_array_init(symbols);
|
static inline void symbol_clear(VectorSymbol *symbols) {
|
||||||
}
|
for (size_t i = 0; i < vector_size(symbols); ++i) {
|
||||||
static inline void symbol_clear_symbols(VectorSymbol *symbols) {
|
symbol_free(&vector_at(symbols, i));
|
||||||
for (size_t i = 0; i < sc_array_size(symbols); ++i) {
|
|
||||||
symbol_free(&sc_array_at(symbols, i));
|
|
||||||
}
|
}
|
||||||
sc_array_clear(symbols);
|
vector_clear(symbols);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void symbol_term_symbols(VectorSymbol *symbols) {
|
static inline void symbol_term(VectorSymbol *symbols) {
|
||||||
symbol_clear_symbols(symbols);
|
symbol_clear(symbols);
|
||||||
sc_array_term(symbols);
|
vector_term(symbols);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void symbol_add(VectorSymbol *symbols, Symbol symbol) {
|
||||||
|
vector_add(symbols, symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol *symbol_find(VectorSymbol *symbols, Symbol *symbol);
|
Symbol *symbol_find(VectorSymbol *symbols, Symbol *symbol);
|
||||||
|
|
||||||
SymbolBind symbol_bind_from_efibind(u32 efi_bind);
|
SymbolBind symbol_bind_from_efibind(u32 efi_bind);
|
||||||
SymbolType symbol_type_from_efitype(u32 efi_type);
|
SymbolType symbol_type_from_efitype(u32 efi_type);
|
||||||
|
|
||||||
|
|||||||
40
src/vector.h
40
src/vector.h
@@ -1,9 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* Fe use sc library sc_array, but for naming consistency we wrap
|
||||||
|
* the names for our own.
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../3rd/sc/array/sc_array.h"
|
#include "../3rd/sc/array/sc_array.h"
|
||||||
|
|
||||||
typedef struct sc_array_32 VectorU32;
|
#define vector_def(T, name) \
|
||||||
typedef struct sc_array_64 VectorU64;
|
typedef struct Vector##name { \
|
||||||
typedef struct sc_array_double VectorDouble;
|
bool oom; \
|
||||||
typedef struct sc_array_str VectorStr;
|
size_t cap; \
|
||||||
typedef struct sc_array_ptr VectorPtr;
|
size_t size; \
|
||||||
|
/* NOLINTNEXTLINE */ \
|
||||||
|
T *elems; \
|
||||||
|
} Vector##name
|
||||||
|
|
||||||
|
#define vector_init(a) sc_array_init((a))
|
||||||
|
#define vector_term(a) sc_array_term((a))
|
||||||
|
#define vector_add(a, k) sc_array_add((a), (k))
|
||||||
|
#define vector_clear(a) sc_array_clear((a))
|
||||||
|
#define vector_oom(a) sc_array_oom((a))
|
||||||
|
#define vector_at(a, i) sc_array_at((a), (i))
|
||||||
|
#define vector_size(a) sc_array_size((a))
|
||||||
|
#define vector_del(a, i) sc_array_del((a), (i))
|
||||||
|
#define vector_del_unordered(a, i) sc_array_del_unordered((a), (i))
|
||||||
|
#define vector_del_last(a) sc_array_del_last((a))
|
||||||
|
#define vector_sort(a, cmp) sc_array_sort((a), (cmp))
|
||||||
|
#define vector_last(a) sc_array_last((a))
|
||||||
|
#define vector_foreach(a, elem) sc_array_foreach((a), (elem))
|
||||||
|
|
||||||
|
vector_def(int, Int);
|
||||||
|
vector_def(unsigned int, Uint);
|
||||||
|
vector_def(uint32_t, U32);
|
||||||
|
vector_def(uint64_t, U64);
|
||||||
|
vector_def(double, Double);
|
||||||
|
vector_def(const char *, Str);
|
||||||
|
vector_def(void *, Ptr);
|
||||||
|
|||||||
Reference in New Issue
Block a user