Files
Arquivotheca.Solaris-2.5/cmd/ptools/libproc/dynlib.c
seta75D 7c4988eac0 Init
2021-10-11 19:38:01 -03:00

354 lines
7.2 KiB
C
Executable File

#ident "@(#)dynlib.c 1.1 94/11/10 SMI"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <dirent.h>
#include <limits.h>
#include <link.h>
#include <libelf.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/signal.h>
#include <sys/fault.h>
#include <sys/syscall.h>
#include <sys/procfs.h>
#include <sys/mkdev.h>
#include "dynlib.h"
typedef struct {
dev_t dev;
ino_t ino;
char * name;
} lib_t;
static lib_t *lib = NULL;
static int Nlib = 0;
static int nlib = 0;
void
clear_names()
{
lib_t * lp;
lib_t * elp;
for (lp = &lib[0], elp = &lib[nlib]; lp < elp; lp++)
free(lp->name);
nlib = 0;
}
static void
add_name(dev_t dev, ino_t ino, const char * name)
{
lib_t * lp;
lib_t * elp;
if (nlib >= Nlib) {
lib_t *newlib;
int newNlib;
if (Nlib == 0)
newNlib = 200;
else
newNlib = 2 * Nlib;
if ((newlib = malloc(newNlib * sizeof(lib_t))) == NULL)
return;
if (lib) {
(void) memcpy((char *)newlib, (char *)lib,
Nlib*sizeof(lib_t));
free(lib);
}
lib = newlib;
Nlib = newNlib;
}
for (lp = &lib[0], elp = &lib[nlib]; lp < elp; lp++)
if (lp->dev == dev && lp->ino == ino)
break;
/* duplicate entry? */
if (lp != elp)
return;
/* new entry */
nlib++;
lp->dev = dev;
lp->ino = ino;
if ((lp->name = malloc((unsigned)strlen(name)+1)) != NULL)
(void) strcpy(lp->name, name);
else
nlib--;
}
void
load_lib_name(const char * name)
{
struct stat statb;
if (stat(name, &statb) == 0 && S_ISREG(statb.st_mode))
add_name(statb.st_dev, statb.st_ino, name);
}
void
load_lib_dir(const char * dir)
{
char name[1024];
int dlen;
DIR * dirp;
struct dirent * dentp;
(void) strcpy(name, dir);
if ((dirp = opendir(name)) == NULL) {
/* perror(name); */
return;
}
dlen = strlen(name);
name[dlen++] = '/';
/* for each file in dir --- */
while (dentp = readdir(dirp)) {
char * s;
struct stat statb;
if (dentp->d_name[0] != '.'
&& (s = strstr(dentp->d_name, ".so"))
&& (*(s += 3) == '.' || *s == '\0')
&& strcpy(name+dlen, dentp->d_name)
&& lstat(name, &statb) == 0
&& S_ISREG(statb.st_mode))
add_name(statb.st_dev, statb.st_ino, name);
}
(void) closedir(dirp);
}
/*
* Thanks to Bart Smaalders for the load_ldd_names() algorithm.
* He thanks Rod Evans for the tip regarding DT_DEBUG == &r_debugger.
*/
void
load_ldd_names(int pfd)
{
int i;
int efd;
size_t size;
Elf32_Ehdr elfhdr;
Elf32_Phdr * proghdr = NULL;
Elf32_Phdr * phdr;
Elf32_Dyn * dyn = NULL;
Elf32_Dyn * dynp;
struct stat estat;
struct r_debug r_debugger;
Link_map link_map;
/*
* Open the process's executable file.
*/
if ((efd = ioctl(pfd, PIOCOPENM, NULL)) < 0)
return;
/*
* Get its stat structure.
*/
if (fstat(efd, &estat) != 0 || !S_ISREG(estat.st_mode))
goto out;
/*
* Read in the program header.
*/
if (pread(efd, (char *)&elfhdr, sizeof(elfhdr), 0) != sizeof(elfhdr))
goto out;
/*
* Check if ELF binary - could be a.out
*/
if (strncmp((char *)elfhdr.e_ident, "\177ELF", 4) != 0
|| elfhdr.e_type != ET_EXEC
|| elfhdr.e_version != EV_CURRENT)
goto out;
/*
* Grab program header headers.
*/
size = elfhdr.e_phentsize * elfhdr.e_phnum;
if ((proghdr = malloc(size)) == NULL
|| pread(efd, (char *)proghdr, size, elfhdr.e_phoff) != size)
goto out;
/*
* look for DYNAMIC section
*/
phdr = proghdr;
for (i = 0; i < (int)elfhdr.e_phnum; i++) {
if (phdr->p_type == PT_DYNAMIC)
break;
/*
* We increment by the size of the structure as
* specified in the elf header, rather than the size
* of the structure at compile time. This allows the
* structure to grow later w/o obsoleting this binary
*/
/* LINTED possible alignment error */
phdr = (Elf32_Phdr *)((char *)phdr + elfhdr.e_phentsize);
}
if (phdr->p_type != PT_DYNAMIC) /* statically linked */
goto out;
/*
* Load the dynamic section from process memory.
*
* As I read the docs, I should be using the in memory size rather
* than the filesize. However, the in meory size is zero, and
* this works.
*/
size = phdr->p_filesz;
if ((dyn = malloc(size)) == NULL
|| pread(pfd, (void *)dyn, size, phdr->p_vaddr) != size)
goto out;
for (dynp = dyn, i = 0; i < size; dynp++, i += sizeof(*dynp))
if (dynp->d_tag == DT_DEBUG)
break;
if (dynp->d_tag != DT_DEBUG)
goto out;
/*
* ld.so.1 patches the value of DT_DEBUG to point to the structure
* r_debug defined in link.h. Load this structure from process memory.
*/
if (pread(pfd, &r_debugger, sizeof(r_debugger), dynp->d_un.d_ptr)
!= sizeof(r_debugger))
goto out;
/*
* Traverse the linked list of mapped ELF objects,
* adding each one to the set of known libraries.
*/
link_map.l_next = r_debugger.r_map;
while (link_map.l_next) {
struct stat statb;
char name[PATH_MAX+1]; /* should be large enough */
name[PATH_MAX] = '\0'; /* paranoia */
if (pread(pfd, &link_map, sizeof(link_map),
(long)link_map.l_next) != sizeof(link_map))
break;
if (read_string(pfd, name, PATH_MAX+1, (long)link_map.l_name)
<= 0)
break;
/*
* If the object is a regular file with a full pathname and
* if it isn't the executable file itself, add it to the set.
*/
if (name[0] == '/'
&& stat(name, &statb) == 0
&& S_ISREG(statb.st_mode)
&& !(statb.st_dev == estat.st_dev
&& statb.st_ino == estat.st_ino))
add_name(statb.st_dev, statb.st_ino, name);
}
out:
if (dyn)
free(dyn);
if (proghdr)
free(proghdr);
(void) close(efd);
}
/*
* Get the dev/ino info of the executable from the PATH.
*/
void
load_exec_name(const char *name)
{
char *path = NULL;
char *comp;
const char *nameptr;
struct stat statb;
char buff[1024];
if (*name == '/') { /* fully qualified */
if (access(nameptr = name, X_OK))
return;
} else { /* not fully qualified */
if ((path = getenv("PATH")) == NULL)
return;
path = strdup(path);
for (comp = strtok(path, ":"); comp; comp = strtok(NULL, ":")) {
strcpy(buff, comp);
strcat(buff, "/");
strcat(buff, name);
if (access(buff, X_OK) == 0) {
nameptr = buff;
break;
}
}
}
if (stat(nameptr, &statb) == 0 && S_ISREG(statb.st_mode))
add_name(statb.st_dev, statb.st_ino, nameptr);
if (path)
free(path);
return;
}
static lib_t executable = { NODEV , 0 , NULL };
static char exec_name[512];
void
make_exec_name(const char * name)
{
struct stat statb;
if (stat(name, &statb) == 0 && S_ISREG(statb.st_mode)) {
executable.dev = statb.st_dev;
executable.ino = statb.st_ino;
executable.name = exec_name;
(void) strcpy(exec_name, name);
}
}
/* returns NULL if name not found */
char *
lookup_raw_file(dev_t dev, ino_t ino)
{
lib_t * lp;
lib_t * elp;
if (executable.dev == dev && executable.ino == ino)
return executable.name;
for (lp = &lib[0], elp = &lib[nlib]; lp < elp; lp++)
if (lp->dev == dev && lp->ino == ino)
return lp->name;
return NULL;
}
/* never returns NULL */
char *
lookup_file(dev_t dev, ino_t ino)
{
static char buf[40];
char *name = lookup_raw_file(dev, ino);
if (name == NULL)
(void) sprintf(name = buf, "dev: %3d,%-3d ino: %d",
major(dev), minor(dev), ino);
return name;
}
char *
index_name(int index)
{
if (index < 0 || index >= nlib)
return NULL;
return lib[index].name;
}