#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#include "stuff/bool.h"
#include "stuff/ofile.h"
#include "stuff/errors.h"
#include "stuff/allocate.h"
char *progname = NULL;
struct flags {
enum bool treat_as_data;
enum bool print_offsets;
enum bool all_sections;
unsigned long minimum_length;
};
static void usage(
void);
static void ofile_processor(
struct ofile *ofile,
char *arch_name,
void *cookie);
static void ofile_find(
char *addr,
unsigned long size,
unsigned long offset,
struct flags *flags);
static void find(
unsigned long cnt,
struct flags *flags);
static enum bool dirt(
int c);
int
main(
int argc,
char **argv,
char **envp)
{
struct flags flags;
unsigned long i, j, nfiles;
char *endp;
struct arch_flag *arch_flags;
unsigned long narch_flags;
enum bool all_archs;
progname = argv[0];
nfiles = 0;
arch_flags = NULL;
narch_flags = 0;
all_archs = FALSE;
flags.treat_as_data = FALSE;
flags.print_offsets = FALSE;
flags.all_sections = FALSE;
flags.minimum_length = 4;
for(i = 1; i < argc; i++){
if(argv[i][0] == '-'){
if(argv[i][1] == '\0')
flags.treat_as_data = TRUE;
else if(strcmp(argv[i], "-arch") == 0){
if(i + 1 == argc){
error("missing argument(s) to %s option", argv[i]);
usage();
}
if(strcmp("all", argv[i+1]) == 0){
all_archs = TRUE;
}
else{
arch_flags = reallocate(arch_flags,
(narch_flags + 1) * sizeof(struct arch_flag));
if(get_arch_from_flag(argv[i+1],
arch_flags + narch_flags) == 0){
error("unknown architecture specification flag: "
"%s %s", argv[i], argv[i+1]);
arch_usage();
usage();
}
narch_flags++;
}
i++;
}
else{
endp = NULL;
for(j = 1; argv[i][j] != '\0' && endp == NULL; j++){
switch(argv[i][j]){
case 'o':
flags.print_offsets = TRUE;
break;
case 'a':
flags.all_sections = TRUE;
break;
default:
if(!isdigit(argv[i][j])){
error("unknown flag: %s", argv[i]);
usage();
}
flags.minimum_length = strtoul(argv[i]+j,&endp,10);
if(*endp != '\0'){
error("invalid decimal number in flag: %s",
argv[i]);
usage();
}
}
}
}
}
else{
nfiles++;
}
}
if(nfiles != 0){
for(i = 1; i < argc; i++){
if(argv[i][0] != '-'){
if(flags.treat_as_data == TRUE){
if(freopen(argv[i], "r", stdin) == NULL)
system_error("can't open: %s", argv[i]);
rewind(stdin);
find(ULONG_MAX, &flags);
}
else
ofile_process(argv[i], arch_flags, narch_flags,
all_archs, TRUE, TRUE, TRUE,
ofile_processor,&flags);
}
else if(strcmp(argv[i], "-arch") == 0)
i++;
}
}
else{
find(ULONG_MAX, &flags);
}
if(errors == 0)
return(EXIT_SUCCESS);
else
return(EXIT_FAILURE);
}
static
void
usage(
void)
{
fprintf(stderr, "Usage: %s [-] [-a] [-o] "
"[[-arch <arch_flag>] ...] [file ...]\n", progname);
exit(EXIT_FAILURE);
}
static
void
ofile_processor(
struct ofile *ofile,
char *arch_name,
void *cookie)
{
char *addr;
unsigned long offset, size, i, j;
struct flags *flags;
struct load_command *lc;
struct segment_command *sg;
struct section *s;
flags = (struct flags *)cookie;
if(ofile->object_addr == NULL){
if(ofile->file_type == OFILE_FAT && ofile->arch_flag.cputype != 0){
addr = ofile->file_addr + ofile->fat_archs[ofile->narch].offset;
size = ofile->fat_archs[ofile->narch].size;
offset = ofile->fat_archs[ofile->narch].offset;
}
else{
addr = ofile->file_addr;
size = ofile->file_size;
offset = 0;
}
if(ofile->member_ar_hdr != NULL)
ofile_find(addr + ofile->member_offset,
strtoul(ofile->member_ar_hdr->ar_size, NULL, 10),
offset + ofile->member_offset,
flags);
else
ofile_find(addr, size, offset, flags);
return;
}
lc = ofile->load_commands;
for(i = 0; i < ofile->mh->ncmds; i++){
if(lc->cmd == LC_SEGMENT){
sg = (struct segment_command *)lc;
s = (struct section *)((char *)sg +
sizeof(struct segment_command));
for(j = 0; j < sg->nsects; j++){
if(flags->all_sections){
if((s->flags & S_ZEROFILL) != S_ZEROFILL){
ofile_find(ofile->object_addr + s->offset,
s->size, s->offset, flags);
}
}
else{
if((s->flags & S_ZEROFILL) != S_ZEROFILL &&
(strcmp(s->sectname, SECT_TEXT) != 0 ||
strcmp(s->segname, SEG_TEXT) != 0)){
ofile_find(ofile->object_addr + s->offset,
s->size, s->offset, flags);
}
}
s++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
static
void
ofile_find(
char *addr,
unsigned long size,
unsigned long offset,
struct flags *flags)
{
unsigned long i, string_length;
char c, *string;
string = addr;
string_length = 0;
for(i = 0; i < size; i++){
c = addr[i];
if(c == '\n' || dirt(c) || i == size - 1){
if(string_length >= flags->minimum_length){
if(flags->print_offsets)
printf("%7lu ", offset + (string - addr));
printf("%.*s\n", (int)string_length, string);
}
string = addr + i + 1;
string_length = 0;
}
else{
string_length++;
}
}
}
static
void
find(
unsigned long cnt,
struct flags *flags)
{
static char buf[BUFSIZ];
register char *cp;
register int c, cc;
cp = buf, cc = 0;
for (; cnt != 0; cnt--) {
c = getc(stdin);
if (c == '\n' || dirt(c) || cnt == 0) {
if (cp > buf && cp[-1] == '\n')
--cp;
*cp++ = 0;
if (cp > &buf[flags->minimum_length]) {
if (flags->print_offsets == TRUE)
printf("%7ld ", ftell(stdin) - cc - 1);
printf("%s\n", buf);
}
cp = buf, cc = 0;
} else {
if (cp < &buf[sizeof buf - 2])
*cp++ = c;
cc++;
}
if (ferror(stdin) || feof(stdin))
break;
}
}
static
enum bool
dirt(
int c)
{
switch(c){
case '\n':
case '\f':
return(FALSE);
case 0177:
return(TRUE);
default:
if(c > 0200 || c < ' ')
return(TRUE);
else
return(FALSE);
}
}