|
|
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 |
|
|
|
88fa98 |
if ((fdout = openat(fdcwd,output,O_CREAT|O_TRUNC|O_WRONLY,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 |
}
|