From bbf27c0ae5b4cd69e031f7e53bd2456fbc17ab2b Mon Sep 17 00:00:00 2001
From: midipix <writeonce@midipix.org>
Date: Tue, 27 Feb 2024 09:57:51 +0000
Subject: archiver api: added slbt_ar_update_syminfo() (nm output to symbol
 info vector).

---
 src/arbits/slbt_archive_meta.c    |   9 ++
 src/arbits/slbt_archive_syminfo.c | 268 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 277 insertions(+)
 create mode 100644 src/arbits/slbt_archive_syminfo.c

(limited to 'src/arbits')

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;
+}
-- 
cgit v1.2.3