summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/slibtool/slibtool_arbits.h9
-rw-r--r--project/common.mk1
-rw-r--r--src/arbits/slbt_archive_meta.c9
-rw-r--r--src/arbits/slbt_archive_syminfo.c268
-rw-r--r--src/internal/slibtool_ar_impl.h7
5 files changed, 294 insertions, 0 deletions
diff --git a/include/slibtool/slibtool_arbits.h b/include/slibtool/slibtool_arbits.h
index 8168f04..8ab8d0c 100644
--- a/include/slibtool/slibtool_arbits.h
+++ b/include/slibtool/slibtool_arbits.h
@@ -166,6 +166,15 @@ struct ar_meta_armap_common_64 {
const char * ar_string_table;
};
+struct ar_meta_symbol_info {
+ const char * ar_archive_name;
+ const char * ar_object_name;
+ const char * ar_symbol_name;
+ const char * ar_symbol_type;
+ uint64_t ar_symbol_value;
+ uint64_t ar_symbol_size;
+};
+
struct ar_meta_armap_info {
const struct ar_meta_armap_common_32 * ar_armap_common_32;
const struct ar_meta_armap_common_64 * ar_armap_common_64;
diff --git a/project/common.mk b/project/common.mk
index 04cf88c..1b9a880 100644
--- a/project/common.mk
+++ b/project/common.mk
@@ -6,6 +6,7 @@ API_SRCS = \
src/arbits/slbt_archive_meta.c \
src/arbits/slbt_archive_store.c \
src/arbits/slbt_archive_symfile.c \
+ src/arbits/slbt_archive_syminfo.c \
src/arbits/slbt_armap_bsd_32.c \
src/arbits/slbt_armap_bsd_64.c \
src/arbits/slbt_armap_sysv_32.c \
diff --git a/src/arbits/slbt_archive_meta.c b/src/arbits/slbt_archive_meta.c
index a966c26..e5d0a9f 100644
--- a/src/arbits/slbt_archive_meta.c
+++ b/src/arbits/slbt_archive_meta.c
@@ -40,6 +40,12 @@ static int slbt_ar_free_archive_meta_impl(struct slbt_archive_meta_impl * meta,
if (meta->namestrs)
free(meta->namestrs);
+ if (meta->syminfo)
+ free(meta->syminfo);
+
+ if (meta->syminfv)
+ free(meta->syminfv);
+
if (meta->memberv)
free(meta->memberv);
@@ -55,6 +61,9 @@ static int slbt_ar_free_archive_meta_impl(struct slbt_archive_meta_impl * meta,
if (meta->mapstrv)
free(meta->mapstrv);
+ if (meta->nminfo)
+ slbt_lib_free_txtfile_ctx(meta->nminfo);
+
free(meta);
}
diff --git a/src/arbits/slbt_archive_syminfo.c b/src/arbits/slbt_archive_syminfo.c
new file mode 100644
index 0000000..525608b
--- /dev/null
+++ b/src/arbits/slbt_archive_syminfo.c
@@ -0,0 +1,268 @@
+/*******************************************************************/
+/* slibtool: a skinny libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <limits.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <slibtool/slibtool.h>
+#include "slibtool_ar_impl.h"
+#include "slibtool_driver_impl.h"
+#include "slibtool_dprintf_impl.h"
+#include "slibtool_snprintf_impl.h"
+#include "slibtool_errinfo_impl.h"
+
+static const char ar_symbol_type_A[] = "A";
+static const char ar_symbol_type_B[] = "B";
+static const char ar_symbol_type_C[] = "C";
+static const char ar_symbol_type_D[] = "D";
+static const char ar_symbol_type_G[] = "G";
+static const char ar_symbol_type_I[] = "I";
+static const char ar_symbol_type_R[] = "R";
+static const char ar_symbol_type_S[] = "S";
+static const char ar_symbol_type_T[] = "T";
+static const char ar_symbol_type_W[] = "W";
+
+static const char * const ar_symbol_type['Z'-'A'] = {
+ ['A'-'A'] = ar_symbol_type_A,
+ ['B'-'A'] = ar_symbol_type_B,
+ ['C'-'A'] = ar_symbol_type_C,
+ ['D'-'A'] = ar_symbol_type_D,
+ ['G'-'A'] = ar_symbol_type_G,
+ ['I'-'A'] = ar_symbol_type_I,
+ ['R'-'A'] = ar_symbol_type_R,
+ ['S'-'A'] = ar_symbol_type_S,
+ ['T'-'A'] = ar_symbol_type_T,
+ ['W'-'A'] = ar_symbol_type_W,
+};
+
+static void slbt_ar_update_syminfo_child(
+ char * program,
+ char * arname,
+ int fdout)
+{
+ char * argv[6];
+
+ argv[0] = program;
+ argv[1] = "-P";
+ argv[2] = "-A";
+ argv[3] = "-g";
+ argv[4] = arname;
+ argv[5] = 0;
+
+ if (dup2(fdout,1) == 1)
+ execvp(program,argv);
+
+ _exit(EXIT_FAILURE);
+}
+
+static int slbt_obtain_nminfo(
+ struct slbt_archive_ctx_impl * ictx,
+ struct slbt_exec_ctx * ectx,
+ const struct slbt_driver_ctx * dctx,
+ struct slbt_archive_meta_impl * mctx)
+{
+ int pos;
+ int fdcwd;
+ pid_t pid;
+ pid_t rpid;
+ int fdout;
+ char arname [PATH_MAX];
+ char output [PATH_MAX];
+ char program[PATH_MAX];
+
+ /* fdcwd */
+ fdcwd = slbt_driver_fdcwd(dctx);
+
+ /* program */
+ if (slbt_snprintf(program,sizeof(program),
+ "%s",dctx->cctx->host.nm) < 0)
+ return SLBT_BUFFER_ERROR(dctx);
+
+ /* output (.nm suffix, buf treat as .syminfo) */
+ pos = slbt_snprintf(
+ arname,sizeof(arname)-8,"%s",
+ ictx->path);
+
+ strcpy(output,arname);
+ strcpy(&output[pos],".nm");
+
+ /* fork */
+ fdout = openat(fdcwd,output,O_CREAT|O_TRUNC|O_WRONLY,0644);
+
+ if ((pid = fork()) < 0) {
+ close(fdout);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+
+ /* child */
+ if (pid == 0)
+ slbt_ar_update_syminfo_child(
+ program,arname,fdout);
+
+ /* parent */
+ ectx->pid = pid;
+
+ rpid = waitpid(
+ pid,
+ &ectx->exitcode,
+ 0);
+
+ if (rpid < 0) {
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ } else if (ectx->exitcode < 0) {
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+ }
+
+ if (slbt_lib_get_txtfile_ctx(
+ dctx,output,
+ &mctx->nminfo) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ return 0;
+}
+
+static int slbt_get_symbol_nm_info(
+ struct slbt_archive_ctx * actx,
+ struct slbt_archive_meta_impl * mctx,
+ uint64_t idx)
+{
+ int cint;
+ const char ** pline;
+ const char * mark;
+ const char * cap;
+ const char * objname;
+ const char * symname;
+ struct ar_meta_symbol_info * syminfo;
+ struct ar_meta_member_info ** pmember;
+
+ symname = mctx->symstrv[idx];
+ syminfo = &mctx->syminfo[idx];
+
+ for (pline=mctx->nminfo->txtlinev; *pline; pline++) {
+ mark = *pline;
+
+ if (!(mark = strchr(mark,']')))
+ return -1;
+
+ if ((*++mark != ':') || (*++mark != ' '))
+ return -1;
+
+ cap = ++mark;
+
+ for (; *cap && !isspace((cint = *cap)); )
+ cap++;
+
+ if (*cap != ' ')
+ return -1;
+
+ if (!(strncmp(symname,mark,cap-mark))) {
+ mark = ++cap;
+
+ /* space only according to posix, but ... */
+ if (mark[1] && (mark[1] != ' '))
+ return -1;
+
+ switch (mark[0]) {
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'G':
+ case 'I':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'W':
+ syminfo->ar_symbol_type = ar_symbol_type[mark[0]-'A'];
+ break;
+
+ default:
+ break;
+ }
+
+ if (syminfo->ar_symbol_type) {
+ syminfo->ar_archive_name = *actx->path;
+ syminfo->ar_symbol_name = symname;
+
+ if (!(mark = strchr(*pline,'[')))
+ return -1;
+
+ if (!(cap = strchr(++mark,']')))
+ return -1;
+ }
+
+ pmember = mctx->memberv;
+
+ for (; *pmember && !syminfo->ar_object_name; ) {
+ objname = (*pmember)->ar_file_header.ar_member_name;
+
+ if (!(strncmp(objname,mark,cap-mark)))
+ syminfo->ar_object_name = objname;
+
+ pmember++;
+ }
+
+ mctx->syminfv[idx] = syminfo;
+ }
+ }
+
+ return (mctx->syminfv[idx] ? 0 : (-1));
+}
+
+slbt_hidden int slbt_ar_update_syminfo(
+ struct slbt_archive_ctx * actx,
+ struct slbt_exec_ctx * ectx)
+{
+ const struct slbt_driver_ctx * dctx;
+ struct slbt_archive_ctx_impl * ictx;
+ struct slbt_archive_meta_impl * mctx;
+ uint64_t idx;
+
+ /* driver context, etc. */
+ ictx = slbt_get_archive_ictx(actx);
+ mctx = slbt_archive_meta_ictx(ictx->meta);
+ dctx = ictx->dctx;
+
+ /* nm -P -A -g */
+ if (slbt_obtain_nminfo(ictx,ectx,dctx,mctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+ /* free old syminfo vector */
+ if (mctx->syminfv)
+ free(mctx->syminfv);
+
+ /* syminfo vector: armap symbols only */
+ if (!(mctx->syminfo = calloc(
+ mctx->armaps.armap_nsyms + 1,
+ sizeof(*mctx->syminfo))))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ if (!(mctx->syminfv = calloc(
+ mctx->armaps.armap_nsyms + 1,
+ sizeof(*mctx->syminfv))))
+ return SLBT_SYSTEM_ERROR(dctx,0);
+
+ /* do the thing */
+ for (idx=0; idx<mctx->armaps.armap_nsyms; idx++)
+ if (slbt_get_symbol_nm_info(actx,mctx,idx) < 0)
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_FLOW_ERROR);
+ /* yay */
+ return 0;
+}
diff --git a/src/internal/slibtool_ar_impl.h b/src/internal/slibtool_ar_impl.h
index e5bfca8..8ebf68f 100644
--- a/src/internal/slibtool_ar_impl.h
+++ b/src/internal/slibtool_ar_impl.h
@@ -44,9 +44,12 @@ struct slbt_archive_meta_impl {
const char ** symstrv;
const char ** mapstrv;
off_t * offsetv;
+ struct ar_meta_symbol_info * syminfo;
+ struct ar_meta_symbol_info ** syminfv;
struct ar_meta_member_info ** memberv;
struct ar_meta_member_info * members;
struct ar_armaps_impl armaps;
+ struct slbt_txtfile_ctx * nminfo;
struct slbt_archive_meta armeta;
};
@@ -74,6 +77,10 @@ int slbt_update_mapstrv(
const struct slbt_driver_ctx * dctx,
struct slbt_archive_meta_impl * m);
+int slbt_ar_update_syminfo(
+ struct slbt_archive_ctx * actx,
+ struct slbt_exec_ctx * ectx);
+
static inline struct slbt_archive_meta_impl * slbt_archive_meta_ictx(const struct slbt_archive_meta * meta)
{
uintptr_t addr;