#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.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;
char *offset_format;
enum bool all_sections;
uint32_t minimum_length;
};
static void usage(
void);
static void ofile_processor(
struct ofile *ofile,
char *arch_name,
void *cookie);
static void ofile_find(
char *addr,
uint32_t size,
uint32_t offset,
struct flags *flags);
static void find(
uint32_t cnt,
struct flags *flags);
static enum bool dirt(
int c);
int
main(
int argc,
char **argv,
char **envp)
{
struct flags flags;
int i;
uint32_t j, nfiles;
char *endp;
struct arch_flag *arch_flags;
uint32_t narch_flags;
enum bool all_archs, rest_args_files, use_member_syntax;
struct stat stat_buf;
progname = argv[0];
nfiles = 0;
arch_flags = NULL;
narch_flags = 0;
all_archs = FALSE;
flags.treat_as_data = FALSE;
flags.print_offsets = FALSE;
flags.offset_format = NULL;
flags.all_sections = FALSE;
flags.minimum_length = 4;
rest_args_files = FALSE;
for(i = 1; i < argc; i++){
if(rest_args_files == FALSE && argv[i][0] == '-'){
if(argv[i][1] == '\0')
flags.treat_as_data = TRUE;
else if(strcmp(argv[i], "--") == 0)
rest_args_files = 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 if(strcmp(argv[i], "-n") == 0){
if(i + 1 == argc){
error("missing argument to %s option", argv[i]);
usage();
}
flags.minimum_length = strtoul(argv[i+1], &endp, 10);
if(*endp != '\0'){
error("invalid decimal number in option: %s %s",
argv[i], argv[i+1]);
usage();
}
i++;
}
else if(strcmp(argv[i], "-t") == 0){
if(i + 1 == argc){
error("missing argument to %s option", argv[i]);
usage();
}
if(argv[i+1][1] != '\0'){
error("invalid argument to option: %s %s",
argv[i], argv[i+1]);
usage();
}
switch(argv[i+1][0]){
case 'd':
flags.print_offsets = TRUE;
flags.offset_format = "%d";
break;
case 'o':
flags.print_offsets = TRUE;
flags.offset_format = "%o";
break;
case 'x':
flags.print_offsets = TRUE;
flags.offset_format = "%x";
break;
default:
error("invalid argument to option: %s %s",
argv[i], argv[i+1]);
usage();
}
i++;
}
else{
endp = NULL;
for(j = 1; argv[i][j] != '\0' && endp == NULL; j++){
switch(argv[i][j]){
case 'o':
flags.print_offsets = TRUE;
flags.offset_format = "%7lu";
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++;
}
}
rest_args_files = FALSE;
if(nfiles != 0){
for(i = 1; i < argc; i++){
if(argv[i][0] != '-' || rest_args_files == TRUE){
if(flags.treat_as_data == TRUE){
if(freopen(argv[i], "r", stdin) == NULL)
system_error("can't open: %s", argv[i]);
rewind(stdin);
find(UINT_MAX, &flags);
}
else{
if(stat(argv[i], &stat_buf) == 0)
use_member_syntax = FALSE;
else
use_member_syntax = TRUE;
ofile_process(argv[i], arch_flags, narch_flags,
all_archs, TRUE, TRUE, use_member_syntax,
ofile_processor,&flags);
}
}
else if(strcmp(argv[i], "-arch") == 0 ||
strcmp(argv[i], "-n") == 0 ||
strcmp(argv[i], "-t") == 0)
i++;
else if(strcmp(argv[i], "--") == 0)
rest_args_files = TRUE;
}
}
else{
find(UINT_MAX, &flags);
}
if(errors == 0)
return(EXIT_SUCCESS);
else
return(EXIT_FAILURE);
}
static
void
usage(
void)
{
fprintf(stderr, "Usage: %s [-] [-a] [-o] [-t format] [-number] "
"[-n number] [[-arch <arch_flag>] ...] [--] [file ...]\n",
progname);
exit(EXIT_FAILURE);
}
static
void
ofile_processor(
struct ofile *ofile,
char *arch_name,
void *cookie)
{
char *addr;
uint32_t offset, size, i, j;
uint32_t ncmds;
struct flags *flags;
struct load_command *lc;
struct segment_command *sg;
struct segment_command_64 *sg64;
struct section *s;
struct section_64 *s64;
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) {
addr = addr + ofile->member_offset;
size = strtoul(ofile->member_ar_hdr->ar_size, NULL, 10);
offset = offset + ofile->member_offset;
}
if(offset >= ofile->file_size)
size = 0;
else if(offset + size > ofile->file_size)
size = ofile->file_size - offset;
ofile_find(addr, size, offset, flags);
return;
}
lc = ofile->load_commands;
if(ofile->mh != NULL)
ncmds = ofile->mh->ncmds;
else
ncmds = ofile->mh64->ncmds;
for(i = 0; i < 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 &&
(s->flags & S_THREAD_LOCAL_ZEROFILL) !=
S_THREAD_LOCAL_ZEROFILL){
addr = ofile->object_addr + s->offset;
offset = s->offset;
size = s->size;
if(offset >= ofile->file_size)
size = 0;
else if(offset + size > ofile->file_size)
size = ofile->file_size - offset;
ofile_find(addr, size, offset, flags);
}
}
else{
if((s->flags & S_ZEROFILL) != S_ZEROFILL &&
(s->flags & S_THREAD_LOCAL_ZEROFILL) !=
S_THREAD_LOCAL_ZEROFILL &&
(strcmp(s->sectname, SECT_TEXT) != 0 ||
strcmp(s->segname, SEG_TEXT) != 0)){
addr = ofile->object_addr + s->offset;
offset = s->offset;
size = s->size;
if(offset >= ofile->file_size)
size = 0;
else if(offset + size > ofile->file_size)
size = ofile->file_size - offset;
ofile_find(addr, size, offset, flags);
}
}
s++;
}
}
else if(lc->cmd == LC_SEGMENT_64){
sg64 = (struct segment_command_64 *)lc;
s64 = (struct section_64 *)((char *)sg64 +
sizeof(struct segment_command_64));
for(j = 0; j < sg64->nsects; j++){
if(flags->all_sections){
if((s64->flags & S_ZEROFILL) != S_ZEROFILL &&
(s64->flags & S_THREAD_LOCAL_ZEROFILL) !=
S_THREAD_LOCAL_ZEROFILL){
addr = ofile->object_addr + s64->offset;
offset = s64->offset;
size = s64->size;
if(offset >= ofile->file_size)
size = 0;
else if(offset + size > ofile->file_size)
size = ofile->file_size - offset;
ofile_find(addr, size, offset, flags);
}
}
else{
if((s64->flags & S_ZEROFILL) != S_ZEROFILL &&
(s64->flags & S_THREAD_LOCAL_ZEROFILL) !=
S_THREAD_LOCAL_ZEROFILL &&
(strcmp(s64->sectname, SECT_TEXT) != 0 ||
strcmp(s64->segname, SEG_TEXT) != 0)){
addr = ofile->object_addr + s64->offset;
offset = s64->offset;
size = s64->size;
if(offset >= ofile->file_size)
size = 0;
else if(offset + size > ofile->file_size)
size = ofile->file_size - offset;
ofile_find(addr, size, offset, flags);
}
}
s64++;
}
}
lc = (struct load_command *)((char *)lc + lc->cmdsize);
}
}
static
void
ofile_find(
char *addr,
uint32_t size,
uint32_t offset,
struct flags *flags)
{
uint32_t 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(flags->offset_format, offset + (string - addr));
printf(" ");
}
if(i == size - 1 && c != '\n')
printf("%.*s\n", (int)string_length + 1, string);
else
printf("%.*s\n", (int)string_length, string);
}
string = addr + i + 1;
string_length = 0;
}
else{
string_length++;
}
}
}
static
void
find(
uint32_t 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(flags->offset_format,
ftell(stdin) - cc - 1);
printf(" ");
}
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);
}
}