summaryrefslogtreecommitdiffhomepage
path: root/src/arbits/slbt_archive_syminfo.c
diff options
context:
space:
mode:
authormidipix <writeonce@midipix.org>2024-02-27 09:57:51 +0000
committermidipix <writeonce@midipix.org>2024-02-28 04:02:41 +0000
commitbbf27c0ae5b4cd69e031f7e53bd2456fbc17ab2b (patch)
tree7b98a32494f969a7ee631f0f2e724107aaf8da21 /src/arbits/slbt_archive_syminfo.c
parent503f2f8123c560cab69786935d8ba42e77f8f2c0 (diff)
downloadslibtool-bbf27c0ae5b4cd69e031f7e53bd2456fbc17ab2b.tar.bz2
slibtool-bbf27c0ae5b4cd69e031f7e53bd2456fbc17ab2b.tar.xz
archiver api: added slbt_ar_update_syminfo() (nm output to symbol info vector).
Diffstat (limited to 'src/arbits/slbt_archive_syminfo.c')
-rw-r--r--src/arbits/slbt_archive_syminfo.c268
1 files changed, 268 insertions, 0 deletions
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;
+}