Blame src/arbits/slbt_archive_syminfo.c

bbf27c
/*******************************************************************/
eac61a
/*  slibtool: a strong libtool implementation, written in C        */
bbf27c
/*  Copyright (C) 2016--2024  SysDeer Technologies, LLC            */
bbf27c
/*  Released under the Standard MIT License; see COPYING.SLIBTOOL. */
bbf27c
/*******************************************************************/
bbf27c
bbf27c
#include <ctype.h>
bbf27c
#include <fcntl.h>
bbf27c
#include <stdio.h>
bbf27c
#include <limits.h>
bbf27c
#include <unistd.h>
bbf27c
#include <string.h>
bbf27c
#include <stdlib.h>
bbf27c
#include <stdbool.h>
bbf27c
#include <inttypes.h>
bbf27c
#include <sys/stat.h>
bbf27c
#include <sys/wait.h>
bbf27c
bbf27c
#include <slibtool/slibtool.h>
bbf27c
#include "slibtool_ar_impl.h"
752cd9
#include "slibtool_coff_impl.h"
bbf27c
#include "slibtool_driver_impl.h"
bbf27c
#include "slibtool_dprintf_impl.h"
c8ac94
#include "slibtool_spawn_impl.h"
bbf27c
#include "slibtool_snprintf_impl.h"
bbf27c
#include "slibtool_errinfo_impl.h"
bbf27c
bbf27c
static const char ar_symbol_type_A[] = "A";
bbf27c
static const char ar_symbol_type_B[] = "B";
bbf27c
static const char ar_symbol_type_C[] = "C";
bbf27c
static const char ar_symbol_type_D[] = "D";
bbf27c
static const char ar_symbol_type_G[] = "G";
bbf27c
static const char ar_symbol_type_I[] = "I";
bbf27c
static const char ar_symbol_type_R[] = "R";
bbf27c
static const char ar_symbol_type_S[] = "S";
bbf27c
static const char ar_symbol_type_T[] = "T";
bbf27c
static const char ar_symbol_type_W[] = "W";
bbf27c
bbf27c
static const char * const ar_symbol_type['Z'-'A'] = {
bbf27c
	['A'-'A'] = ar_symbol_type_A,
bbf27c
	['B'-'A'] = ar_symbol_type_B,
bbf27c
	['C'-'A'] = ar_symbol_type_C,
bbf27c
	['D'-'A'] = ar_symbol_type_D,
bbf27c
	['G'-'A'] = ar_symbol_type_G,
bbf27c
	['I'-'A'] = ar_symbol_type_I,
bbf27c
	['R'-'A'] = ar_symbol_type_R,
bbf27c
	['S'-'A'] = ar_symbol_type_S,
bbf27c
	['T'-'A'] = ar_symbol_type_T,
bbf27c
	['W'-'A'] = ar_symbol_type_W,
bbf27c
};
bbf27c
bbf27c
static void slbt_ar_update_syminfo_child(
bbf27c
	char *	program,
bbf27c
	char *  arname,
bbf27c
	int	fdout)
bbf27c
{
bbf27c
	char *	argv[6];
bbf27c
bbf27c
	argv[0] = program;
bbf27c
	argv[1] = "-P";
bbf27c
	argv[2] = "-A";
bbf27c
	argv[3] = "-g";
bbf27c
	argv[4] = arname;
bbf27c
	argv[5] = 0;
bbf27c
bbf27c
	if (dup2(fdout,1) == 1)
bbf27c
		execvp(program,argv);
bbf27c
bbf27c
	_exit(EXIT_FAILURE);
bbf27c
}
bbf27c
bbf27c
static int slbt_obtain_nminfo(
bbf27c
	struct slbt_archive_ctx_impl *  ictx,
bbf27c
	const struct slbt_driver_ctx *  dctx,
88fa98
	struct slbt_archive_meta_impl * mctx,
88fa98
	int                             fdout)
bbf27c
{
88fa98
	int     ret;
bbf27c
	int     pos;
bbf27c
	int	fdcwd;
88fa98
	int     fdarg;
bbf27c
	pid_t   pid;
bbf27c
	pid_t   rpid;
3077bb
	int     ecode;
0b6090
	char ** argv;
bbf27c
	char    arname [PATH_MAX];
bbf27c
	char    output [PATH_MAX];
bbf27c
	char	program[PATH_MAX];
bbf27c
bbf27c
	/* fdcwd */
bbf27c
	fdcwd = slbt_driver_fdcwd(dctx);
bbf27c
0b6090
	/* tool-specific argument vector */
0b6090
	argv = (slbt_get_driver_ictx(dctx))->host.nm_argv;
0b6090
0b6090
	/* ar alternate argument vector */
0b6090
	if (argv) {
0b6090
		if (slbt_snprintf(program,sizeof(program),
0b6090
				"%s",argv[0]) < 0)
0b6090
			return SLBT_BUFFER_ERROR(dctx);
0b6090
	} else {
0b6090
		if (slbt_snprintf(program,sizeof(program),
0b6090
				"%s",dctx->cctx->host.nm) < 0)
0b6090
			return SLBT_BUFFER_ERROR(dctx);
0b6090
	}
bbf27c
88fa98
	/* arname (.nm suffix, buf treat as .syminfo) */
bbf27c
	pos = slbt_snprintf(
bbf27c
		arname,sizeof(arname)-8,"%s",
bbf27c
		ictx->path);
bbf27c
88fa98
	/* output */
88fa98
	if ((fdarg = fdout) < 0) {
88fa98
		strcpy(output,arname);
88fa98
		strcpy(&output[pos],".nm");
bbf27c
2b3e0a
		if ((fdout = openat(fdcwd,output,O_CREAT|O_TRUNC|O_RDWR,0644)) < 0)
88fa98
			return SLBT_SYSTEM_ERROR(dctx,output);
88fa98
	} else {
88fa98
		strcpy(output,"@nminfo@");
88fa98
	}
bbf27c
88fa98
	/* fork */
c8ac94
	if ((pid = slbt_fork()) < 0) {
bbf27c
		close(fdout);
bbf27c
		return SLBT_SYSTEM_ERROR(dctx,0);
bbf27c
	}
bbf27c
bbf27c
	/* child */
bbf27c
	if (pid == 0)
bbf27c
		slbt_ar_update_syminfo_child(
bbf27c
			program,arname,fdout);
bbf27c
bbf27c
	/* parent */
bbf27c
	rpid = waitpid(
bbf27c
		pid,
3077bb
		&ecode,
bbf27c
		0);
bbf27c
88fa98
	/* nm output */
88fa98
	if ((rpid > 0)  && (ecode == 0))
88fa98
		ret = slbt_impl_get_txtfile_ctx(
88fa98
			dctx,output,fdout,
88fa98
			&mctx->nminfo);
88fa98
88fa98
	if (fdarg < 0)
88fa98
		close(fdout);
88fa98
bbf27c
	if (rpid < 0) {
bbf27c
		return SLBT_SYSTEM_ERROR(dctx,0);
bbf27c
3077bb
	} else if (ecode) {
bbf27c
		return SLBT_CUSTOM_ERROR(
bbf27c
			dctx,
bbf27c
			SLBT_ERR_FLOW_ERROR);
bbf27c
	}
bbf27c
88fa98
	return (ret < 0) ? SLBT_NESTED_ERROR(dctx) : 0;
bbf27c
}
bbf27c
bbf27c
static int slbt_get_symbol_nm_info(
bbf27c
	struct slbt_archive_ctx *       actx,
bbf27c
	struct slbt_archive_meta_impl * mctx,
bbf27c
	uint64_t                        idx)
bbf27c
{
bbf27c
	int                             cint;
bbf27c
	const char **                   pline;
bbf27c
	const char *                    mark;
bbf27c
	const char *                    cap;
bbf27c
	const char *                    objname;
bbf27c
	const char *                    symname;
bbf27c
	struct ar_meta_symbol_info *    syminfo;
bbf27c
	struct ar_meta_member_info **   pmember;
bbf27c
bbf27c
	symname = mctx->symstrv[idx];
bbf27c
	syminfo = &mctx->syminfo[idx];
bbf27c
bbf27c
	for (pline=mctx->nminfo->txtlinev; *pline; pline++) {
bbf27c
		mark = *pline;
bbf27c
bbf27c
		if (!(mark = strchr(mark,']')))
bbf27c
			return -1;
bbf27c
bbf27c
		if ((*++mark != ':') || (*++mark != ' '))
bbf27c
			return -1;
bbf27c
bbf27c
		cap = ++mark;
bbf27c
bbf27c
		for (; *cap && !isspace((cint = *cap)); )
bbf27c
			cap++;
bbf27c
bbf27c
		if (*cap != ' ')
bbf27c
			return -1;
bbf27c
bbf27c
		if (!(strncmp(symname,mark,cap-mark))) {
bbf27c
			mark = ++cap;
bbf27c
bbf27c
			/* space only according to posix, but ... */
bbf27c
			if (mark[1] && (mark[1] != ' '))
bbf27c
				return -1;
bbf27c
bbf27c
			switch (mark[0]) {
bbf27c
				case 'A':
bbf27c
				case 'B':
bbf27c
				case 'C':
bbf27c
				case 'D':
bbf27c
				case 'G':
bbf27c
				case 'I':
bbf27c
				case 'R':
bbf27c
				case 'S':
bbf27c
				case 'T':
bbf27c
				case 'W':
bbf27c
					syminfo->ar_symbol_type = ar_symbol_type[mark[0]-'A'];
bbf27c
					break;
bbf27c
bbf27c
				default:
bbf27c
					break;
bbf27c
			}
bbf27c
bbf27c
			if (syminfo->ar_symbol_type) {
bbf27c
				syminfo->ar_archive_name = *actx->path;
bbf27c
				syminfo->ar_symbol_name  = symname;
bbf27c
bbf27c
				if (!(mark = strchr(*pline,'[')))
bbf27c
					return -1;
bbf27c
bbf27c
				if (!(cap = strchr(++mark,']')))
bbf27c
					return -1;
bbf27c
			}
bbf27c
bbf27c
			pmember = mctx->memberv;
bbf27c
bbf27c
			for (; *pmember && !syminfo->ar_object_name; ) {
bbf27c
				objname = (*pmember)->ar_file_header.ar_member_name;
bbf27c
bbf27c
				if (!(strncmp(objname,mark,cap-mark)))
bbf27c
					syminfo->ar_object_name = objname;
bbf27c
bbf27c
				pmember++;
bbf27c
			}
bbf27c
bbf27c
			mctx->syminfv[idx] = syminfo;
bbf27c
		}
bbf27c
	}
bbf27c
bbf27c
	return (mctx->syminfv[idx] ? 0 : (-1));
bbf27c
}
bbf27c
752cd9
static int slbt_qsort_syminfo_cmp(const void * a, const void * b)
752cd9
{
752cd9
	struct ar_meta_symbol_info ** syminfoa;
752cd9
	struct ar_meta_symbol_info ** syminfob;
752cd9
752cd9
	syminfoa = (struct ar_meta_symbol_info **)a;
752cd9
	syminfob = (struct ar_meta_symbol_info **)b;
752cd9
752cd9
	return strcmp(
752cd9
		(*syminfoa)->ar_symbol_name,
752cd9
		(*syminfob)->ar_symbol_name);
752cd9
}
752cd9
752cd9
static int slbt_coff_qsort_syminfo_cmp(const void * a, const void * b)
752cd9
{
752cd9
	struct ar_meta_symbol_info ** syminfoa;
752cd9
	struct ar_meta_symbol_info ** syminfob;
752cd9
752cd9
	syminfoa = (struct ar_meta_symbol_info **)a;
752cd9
	syminfob = (struct ar_meta_symbol_info **)b;
752cd9
752cd9
	return slbt_coff_qsort_strcmp(
752cd9
		&(*syminfoa)->ar_symbol_name,
752cd9
		&(*syminfob)->ar_symbol_name);
752cd9
}
752cd9
88fa98
static int slbt_ar_update_syminfo_impl(
88fa98
	struct slbt_archive_ctx *       actx,
88fa98
	int                             fdout)
bbf27c
{
bbf27c
	const struct slbt_driver_ctx *  dctx;
bbf27c
	struct slbt_archive_ctx_impl *  ictx;
bbf27c
	struct slbt_archive_meta_impl * mctx;
bbf27c
	uint64_t                        idx;
752cd9
	bool                            fcoff;
bbf27c
bbf27c
	/* driver context, etc. */
bbf27c
	ictx = slbt_get_archive_ictx(actx);
bbf27c
	mctx = slbt_archive_meta_ictx(ictx->meta);
bbf27c
	dctx = ictx->dctx;
bbf27c
bbf27c
	/* nm -P -A -g */
91c8dd
	if (mctx->armaps.armap_nsyms) {
88fa98
		if (slbt_obtain_nminfo(ictx,dctx,mctx,fdout) < 0)
91c8dd
			return SLBT_NESTED_ERROR(dctx);
91c8dd
	} else {
91c8dd
		if (slbt_lib_get_txtfile_ctx(
91c8dd
				dctx,"/dev/null",
91c8dd
				&mctx->nminfo) < 0)
91c8dd
			return SLBT_NESTED_ERROR(dctx);
91c8dd
	}
bbf27c
bbf27c
	/* free old syminfo vector */
bbf27c
	if (mctx->syminfv)
bbf27c
		free(mctx->syminfv);
bbf27c
bbf27c
	/* syminfo vector: armap symbols only */
bbf27c
	if (!(mctx->syminfo = calloc(
bbf27c
			mctx->armaps.armap_nsyms + 1,
bbf27c
			sizeof(*mctx->syminfo))))
bbf27c
		return SLBT_SYSTEM_ERROR(dctx,0);
bbf27c
bbf27c
	if (!(mctx->syminfv = calloc(
bbf27c
			mctx->armaps.armap_nsyms + 1,
bbf27c
			sizeof(*mctx->syminfv))))
bbf27c
		return SLBT_SYSTEM_ERROR(dctx,0);
bbf27c
bbf27c
	/* do the thing */
bbf27c
	for (idx=0; idx<mctx->armaps.armap_nsyms; idx++)
bbf27c
		if (slbt_get_symbol_nm_info(actx,mctx,idx) < 0)
bbf27c
			return SLBT_CUSTOM_ERROR(
bbf27c
				dctx,
bbf27c
				SLBT_ERR_FLOW_ERROR);
752cd9
752cd9
	/* coff-aware sorting */
752cd9
	fcoff  = slbt_host_objfmt_is_coff(dctx);
752cd9
	fcoff |= (mctx->ofmtattr & AR_OBJECT_ATTR_COFF);
752cd9
752cd9
	qsort(mctx->syminfv,mctx->armaps.armap_nsyms,sizeof(*mctx->syminfv),
752cd9
		fcoff ? slbt_coff_qsort_syminfo_cmp : slbt_qsort_syminfo_cmp);
752cd9
bbf27c
	/* yay */
bbf27c
	return 0;
bbf27c
}
88fa98
88fa98
slbt_hidden int slbt_ar_update_syminfo(
88fa98
	struct slbt_archive_ctx * actx)
88fa98
{
88fa98
	return slbt_ar_update_syminfo_impl(actx,(-1));
88fa98
}
88fa98
88fa98
slbt_hidden int slbt_ar_update_syminfo_ex(
88fa98
	struct slbt_archive_ctx * actx,
88fa98
	int                       fdout)
88fa98
{
88fa98
	return slbt_ar_update_syminfo_impl(actx,fdout);
88fa98
}