diff --git a/include/slibtool/slibtool_arbits.h b/include/slibtool/slibtool_arbits.h index 8168f04..8ab8d0c 100644 --- a/include/slibtool/slibtool_arbits.h +++ b/include/slibtool/slibtool_arbits.h @@ -166,6 +166,15 @@ struct ar_meta_armap_common_64 { const char * ar_string_table; }; +struct ar_meta_symbol_info { + const char * ar_archive_name; + const char * ar_object_name; + const char * ar_symbol_name; + const char * ar_symbol_type; + uint64_t ar_symbol_value; + uint64_t ar_symbol_size; +}; + struct ar_meta_armap_info { const struct ar_meta_armap_common_32 * ar_armap_common_32; const struct ar_meta_armap_common_64 * ar_armap_common_64; diff --git a/project/common.mk b/project/common.mk index 04cf88c..1b9a880 100644 --- a/project/common.mk +++ b/project/common.mk @@ -6,6 +6,7 @@ API_SRCS = \ src/arbits/slbt_archive_meta.c \ src/arbits/slbt_archive_store.c \ src/arbits/slbt_archive_symfile.c \ + src/arbits/slbt_archive_syminfo.c \ src/arbits/slbt_armap_bsd_32.c \ src/arbits/slbt_armap_bsd_64.c \ src/arbits/slbt_armap_sysv_32.c \ 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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; idxarmaps.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; +} diff --git a/src/internal/slibtool_ar_impl.h b/src/internal/slibtool_ar_impl.h index e5bfca8..8ebf68f 100644 --- a/src/internal/slibtool_ar_impl.h +++ b/src/internal/slibtool_ar_impl.h @@ -44,9 +44,12 @@ struct slbt_archive_meta_impl { const char ** symstrv; const char ** mapstrv; off_t * offsetv; + struct ar_meta_symbol_info * syminfo; + struct ar_meta_symbol_info ** syminfv; struct ar_meta_member_info ** memberv; struct ar_meta_member_info * members; struct ar_armaps_impl armaps; + struct slbt_txtfile_ctx * nminfo; struct slbt_archive_meta armeta; }; @@ -74,6 +77,10 @@ int slbt_update_mapstrv( const struct slbt_driver_ctx * dctx, struct slbt_archive_meta_impl * m); +int slbt_ar_update_syminfo( + struct slbt_archive_ctx * actx, + struct slbt_exec_ctx * ectx); + static inline struct slbt_archive_meta_impl * slbt_archive_meta_ictx(const struct slbt_archive_meta * meta) { uintptr_t addr;