diff options
Diffstat (limited to 'src/arbits/slbt_archive_syminfo.c')
-rw-r--r-- | src/arbits/slbt_archive_syminfo.c | 268 |
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; +} |