#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include "libproc.h"
#include "Pcontrol.h"
#include "Pisadep.h"
#include "Putil.h"
#define BLKSIZE (8 * 1024)
int
Pscantext(struct ps_prochandle *P)
{
char mapfile[PATH_MAX];
int mapfd;
off_t offset;
off_t endoff;
uintptr_t sysaddr;
int syspri;
int nbytes;
int n2bytes;
int nmappings;
prmap_t *pdp;
prmap_t *prbuf;
unsigned nmap;
uint32_t buf[2 * BLKSIZE / sizeof (uint32_t)];
uchar_t *p;
syspri = 0;
sysaddr = 0;
if (P->sysaddr != 0 &&
(syspri = Pissyscall(P, P->sysaddr)))
sysaddr = P->sysaddr;
if (sysaddr == 0 || syspri != 1)
syspri = Pissyscall_prev(P, P->status.pr_lwp.pr_reg[R_PC],
&sysaddr);
if (sysaddr != 0 && syspri == 1) {
P->sysaddr = sysaddr;
return (0);
}
(void) snprintf(mapfile, sizeof (mapfile), "%s/%d/map",
procfs_path, (int)P->pid);
if ((mapfd = open(mapfile, O_RDONLY)) < 0) {
Pdprintf("failed to open %s: %s\n", mapfile, strerror(errno));
return (-1);
}
nmap = 50;
for (;;) {
prbuf = malloc(nmap * sizeof (prmap_t));
if (prbuf == NULL) {
Pdprintf("Pscantext: failed to allocate buffer\n");
(void) close(mapfd);
return (-1);
}
nmappings = pread(mapfd, prbuf, nmap * sizeof (prmap_t), 0L);
if (nmappings < 0) {
Pdprintf("Pscantext: failed to read map file: %s\n",
strerror(errno));
free(prbuf);
(void) close(mapfd);
return (-1);
}
nmappings /= sizeof (prmap_t);
if (nmappings < nmap)
break;
free(prbuf);
nmap *= 2;
}
(void) close(mapfd);
for (pdp = &prbuf[nmappings - 1]; sysaddr == 0 && syspri != 1 &&
pdp >= prbuf; pdp--) {
offset = (off_t)pdp->pr_vaddr;
endoff = offset + pdp->pr_size;
if ((pdp->pr_mflags&MA_EXEC) == 0 ||
(endoff > P->status.pr_stkbase &&
offset < P->status.pr_stkbase + P->status.pr_stksize) ||
(endoff > P->status.pr_brkbase &&
offset < P->status.pr_brkbase + P->status.pr_brksize))
continue;
(void) lseek(P->asfd, (off_t)offset, 0);
if ((nbytes = read(P->asfd, buf, 2*BLKSIZE)) <= 0)
continue;
if (nbytes < BLKSIZE)
n2bytes = 0;
else {
n2bytes = nbytes - BLKSIZE;
nbytes = BLKSIZE;
}
p = (uchar_t *)buf;
while (sysaddr == 0 && syspri != 1 && offset < endoff) {
if (nbytes <= 0) {
if ((nbytes = n2bytes) <= 0)
break;
(void) memcpy(buf,
&buf[BLKSIZE / sizeof (buf[0])],
nbytes);
n2bytes = 0;
p = (uchar_t *)buf;
if (nbytes == BLKSIZE &&
offset + BLKSIZE < endoff)
n2bytes = read(P->asfd,
&buf[BLKSIZE / sizeof (buf[0])],
BLKSIZE);
}
if (syspri = Pissyscall_text(P, p, nbytes))
sysaddr = offset;
p += sizeof (instr_t);
offset += sizeof (instr_t);
nbytes -= sizeof (instr_t);
}
}
free(prbuf);
if ((P->sysaddr = sysaddr) != 0)
return (0);
else
return (-1);
}