ftp.nice.ch/pub/next/developer/nextsources/debug.s.tar.gz#/debug/gdb/gdb/next/NeXT-xdep.m

This is NeXT-xdep.m in view mode; [Download] [Up]

/* This file is part of GDB.

GDB is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

GDB is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GDB; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */

#import "gdb.h"
#import "symtab.h"
#import "objfiles.h"
#include <errno.h>
#include <string.h>

#import <mach/cthreads.h>
#import <machine/reg.h>
#import <mach-o/nlist.h>

#import <mach-o/loader.h>

#import <objc/maptable.h>
#import <objc/hashtable.h>

#ifdef USE_HAPTABLE
#import "haptable.h"
#endif /* USE_HAPTABLE */

task_t gdb_task;
cthread_t gdb_thread;

#ifndef USE_HAPTABLE
static NXZone *stringHashZone;
static NXHashTable *stringHash;
#else
static NXZone *stringHapZone;
static NXHapTable *stringHap;
#endif

static char *lastSavedString = NULL;
static int debugPrint = 0;

char *find_opath_alias();


#define N_TEXT 4
#define N_DATA 6
#define N_BSS 8

int any_cplusplus = 0;
int force_cplusplus = 0;

char *getShlibName(struct fvmlib_command *libCmd, char **originalName)
{
    char *name, *path, *subpath, *alias;
    int n;
    name = (void *)libCmd + libCmd->fvmlib.name.offset;
    if (path = (char *)find_opath_alias(name, &n)) {
	subpath = name + n;
	alias = xmalloc(strlen(path) + strlen(subpath) + 1);
	strcpy(alias, path);
	strcat(alias, subpath);
	if (originalName)
	    *originalName = name;
	return alias;
    } else {
	if (originalName)
	    *originalName = NULL;
	return name;
    }
}

BOOL static isExecutable(struct mach_header *header)
{
    return (header->filetype == MH_EXECUTE)
           || (header->filetype == MH_OBJECT)
           || (header->filetype == MH_PRELOAD);
}

void symbolFileAddShlibs(SegmentManager *manager)
{
    struct mach_header *header = [manager getMachHeader];
    int nCmds;
    struct load_command *loadCmd;
    char *name, *originalName;
    SegmentManager *shlibManager;
    if ([manager isExecutable]) {
        for (nCmds = header->ncmds,
	     loadCmd = (struct load_command *)(header + 1);
	     nCmds;
	     nCmds--, ((void *)loadCmd) += loadCmd->cmdsize) {
	    if (loadCmd->cmd == LC_LOADFVMLIB) {
		name = getShlibName((struct fvmlib_command *)loadCmd,
		                    &originalName);
		shlibManager = [SegmentManager newShlib: name cpuType: cpuType()];
		if (shlibManager)
		    symfile_add(shlibManager, 0, 0, 0, 0, 0);
		else
		    error("Could not open `%s' as a shlib.", name);
	    }
	}
    }
}

void symbol_file_add_shlibs(SegmentManager *manager)
{
    struct mach_header *header = [manager getMachHeader];
    int nCmds;
    struct load_command *loadCmd;
    char *name;
    if (isExecutable(header)) {
        for (nCmds = header->ncmds,
	     loadCmd = (struct load_command *)(header + 1);
	     nCmds;
	     nCmds--, ((void *)loadCmd) += loadCmd->cmdsize) {
	    if (loadCmd->cmd == LC_LOADFVMLIB) {
		name = getShlibName((struct fvmlib_command *)loadCmd, NULL);
		
	        symbol_file_add(name, 1, 0, 0, 0, 0);
	    }
	}
    }
}

typedef struct _MiscPSymtab {
    unsigned int val;
    struct partial_symtab *pst;
} MiscPSymtab;

static int miscIndex = 0;
static int numAlloced = 0;
#define INITIAL_ALLOC 500;
static MiscPSymtab *miscPSymtabs = NULL;

void
record_minimal_symbol_psymtab(unsigned int val, struct partial_symtab *pst)
{
    if (!val || !isShlibJump(val))
        return;
    
    if (!numAlloced) {
	numAlloced = INITIAL_ALLOC;
	miscPSymtabs = xmalloc(numAlloced * sizeof(*miscPSymtabs));
    } else if (miscIndex == numAlloced) {
	numAlloced *= 2;
	miscPSymtabs = xrealloc(miscPSymtabs,
	                        numAlloced * sizeof(*miscPSymtabs));
    }
    miscPSymtabs[miscIndex].val = val;
    miscPSymtabs[miscIndex].pst = pst;
    miscIndex++;
}

int cmpMiscPSymtabs(const void *arg1, const void *arg2)
{
    const MiscPSymtab *mpst1 = arg1, *mpst2 = arg2;
    if (mpst1->val < mpst2->val)
	return -1;
    else if (mpst1->val == mpst2->val)
	return 0;
    else
	return 1;
}

void
combine_minimal_symbols_psymtabs(struct objfile *objfile)
{
    int count;
    MiscPSymtab *miscPSymtab;
    struct minimal_symbol *minSym, *lastMinSym, *endOfMinSyms;
    
    if (miscIndex) {
	qsort(miscPSymtabs,
	      miscIndex,
	      sizeof(*miscPSymtabs),
	      &cmpMiscPSymtabs);
	minSym = objfile->msymbols;
	endOfMinSyms = minSym + objfile->minimal_symbol_count;
	for (count = miscIndex, miscPSymtab = miscPSymtabs;
	     count;
	     count--, miscPSymtab++) {
	    for (lastMinSym = minSym;
	         (minSym < endOfMinSyms)
		 && (minSym->address != miscPSymtab->val);
		 minSym++);
	    if (minSym < endOfMinSyms) {
		minSym->info = (char *)miscPSymtab->pst;
		minSym++;
	    } else {
		minSym = lastMinSym;
		printf("Value with psymtab but no minimal symbol: %d in %s.\n",
		        miscPSymtab->val, miscPSymtab->pst->filename);
	    }
	}
	free (miscPSymtabs);
	miscPSymtabs = NULL;
	miscIndex = 0;
	numAlloced = 0;
    }
}

#if 0
struct symtab *
symtab_for_misc_function(int ind)
{
    struct misc_function *misc_function;
    struct partial_symtab *psymtab;
    misc_function = misc_function_vector + ind;
    psymtab = misc_function->misc_info;
    if (psymtab)
	return PSYMTAB_TO_SYMTAB(psymtab);
    else
	return NULL;
}

#endif 0    

static NXMapTable *prologueMap = NULL;

typedef union _ProEpInfo {
    unsigned int info;
    struct _Offsets {
	unsigned int prologue : 10;
	unsigned int epilogue : 22;
    } offsets;
} ProEpInfo;

void
mark_prologue(CORE_ADDR function, CORE_ADDR start, CORE_ADDR end)
{
    ProEpInfo proEpInfo;

    proEpInfo.offsets.prologue = start - function;
    proEpInfo.offsets.epilogue =  end - function;
    
    NXMapInsert(prologueMap, (void *)function, (void *)proEpInfo.info);
}

CORE_ADDR
skip_prologue_by_symbol(function)
{
    CORE_ADDR prologue;
    ProEpInfo proEpInfo;
    
    proEpInfo.info = (unsigned)NXMapGet(prologueMap, (void *)function);
    if (proEpInfo.info)
	return function + proEpInfo.offsets.prologue;
    else
	return 0;
}

CORE_ADDR
skip_epilogue(function)
{
    ProEpInfo proEpInfo;
    
    proEpInfo.info = (unsigned)NXMapGet(prologueMap, (void *)function);
    if (proEpInfo.info)
	return (function + proEpInfo.offsets.epilogue);
    else
	return 0;
}

static void
end_command(char *args, int from_tty)
{
    ProEpInfo proEpInfo;
    struct symtab_and_line sal;
    CORE_ADDR function;
    struct block *block;
    
  if (args)
    error ("The \"end\" command does not take any arguments.");
  if (!target_has_execution)
    error ("The program is not running.");
  if (selected_frame == NULL)
    error ("No selected frame.");

    block = block_for_pc(stop_pc);
    function = block->startaddr;
    proEpInfo.info = (unsigned)NXMapGet(prologueMap, (void *)function);
    if (proEpInfo.info) {
	struct breakpoint *breakpoint;
	struct cleanup *old_chain;
        if (stop_pc == function + proEpInfo.offsets.epilogue)
	    error("Already at end of function.");
        if (stop_pc > function + proEpInfo.offsets.epilogue)
	    error("Already past end of function.");
	sal = find_pc_line(function + proEpInfo.offsets.epilogue, 0);
	breakpoint = set_momentary_breakpoint (sal, selected_frame, bp_until);
        old_chain = make_cleanup(delete_breakpoint, breakpoint);
	printf_filtered ("Run till end of ");
	print_stack_frame (selected_frame, selected_frame_level, 0);
	clear_proceed_status ();
	proceed (-1, -1, 0);
	do_cleanups(old_chain);
    } else
	error("Couldn't find end of function.");
}

void
lock_execute_command(int lock)
{
    static mutex_t mutex = NULL;
    static cthread_t lockedThread = 0;
    if (!mutex)
	mutex = mutex_alloc();
    if (lock && (lockedThread != cthread_self())) {
	mutex_lock(mutex);
	lockedThread = cthread_self();
    } else {
	lockedThread = 0;
	mutex_unlock(mutex);
    }
}

void
execute_command_with_lock(char *p, int from_tty)
{
    struct cleanup *cleanups;
    lock_execute_command(YES);
    cleanups = make_cleanup(lock_execute_command, NO);
    execute_command(p, from_tty);
    do_cleanups(cleanups);
}
    
struct opaths {
  char *old, *new;
  struct opaths *next;
} *opaths;

void
opath_alias_command(char *paths, int from_tty)
{
  char *eqsign;
  struct opaths *opath;
  char *old, *new;

  if (!paths) {
    printf("Object File Path Aliases:\n");
    for(opath = opaths; opath; opath = opath->next) 
      printf("%s -> %s\n", opath->old, opath->new);
    return;
  }
  
  /* Should be of the form oldpath=newpath. */
  if (!(eqsign = index(paths, '='))) {
    fprintf(
      stderr,
      "Bad argument to -opath: %s, should be in format oldpath = newpath.\n",
      paths
    );
    return;
  }
  
  /* Skip leading whitespace */
  while(*paths == ' ' || *paths == '\t') paths++;
  old = paths;
  while (*paths != ' ' && *paths != '\t' && *paths != '=') paths++;
  *paths = 0;
  paths = eqsign+1;
  while(*paths == ' ' || *paths == '\t') paths++;
  new = paths;
  while (*paths != ' ' && *paths != '\t' && *paths != '\0') paths++;
  *paths = 0;

  opath = (struct opaths *)malloc(sizeof(struct opaths));
  opath->new = (char *)malloc(strlen(new) + 1);
  strcpy(opath->new, new);
  opath->old = (char *)malloc(strlen(old) + 1);
  strcpy(opath->old, old);
  opath->next = opaths;
  opaths = opath;
}

static void
opath_unalias_command (char *path, int from_tty)
{
  struct opaths *opath;

  if (!path)
    error_no_arg ("old pathname");
  /* Skip leading whitespace */
  while(*path == ' ' || *path == '\t') path++;

  if (opaths) {
    if (!strcmp(opaths->old, path)) {
      opaths = opaths->next;
      return;
    } else {
      for(opath = opaths; opath->next; opath = opath->next) {
	if (!strcmp(opath->next->old, path)) {
	  struct opaths *o;
	  free(opath->next->old);
	  free(opath->next->new);
	  o = opath->next->next;
	  free(opath->next);
	  opath->next = o;
	  return;
	}
      }
    }
  }
  fprintf(stderr, "Can't find %s in opath alias list.\n", path);
}

char *
find_opath_alias(string, ncharsubst)
char *string;
int *ncharsubst;
{
  struct opaths *opath;

  /* Do O-path aliasing. */
  for(opath = opaths; opath; opath = opath->next) {
    if (!strncmp(opath->old, string, strlen(opath->old))) {
      char *newname, *subpath;
      
      *ncharsubst = strlen(opath->old);
      return(opath->new);
    }
  }
  return 0;
}

static char *getNextString(int len)
{
   static char *topOfStrings = NULL;
   static int stringBytesLeft = 0;
   char *nextString;
    
    if (len > stringBytesLeft) {
	stringBytesLeft = vm_page_size;
	vm_allocate(task_self(), (vm_address_t *)&topOfStrings, stringBytesLeft, 1);
    }
    nextString = topOfStrings;
    stringBytesLeft -= len;
    topOfStrings += len;
    return nextString;
}

char *
stringSave(const char *string)
{
    if (!string)
	return NULL;
    if ((string != lastSavedString)
#ifndef USE_HAPTABLE
        && !(lastSavedString = NXHashGet(stringHash, string))) {
#else
        && !(lastSavedString = NXHapGet(stringHap, string))) {
#endif
	int n = strlen(string);
	lastSavedString = getNextString(n + 1);
	bcopy(string, lastSavedString, n + 1);
#ifndef USE_HAPTABLE
	NXHashInsert(stringHash, lastSavedString);
#else
	NXHapInsert(stringHap, lastSavedString);
#endif
    }
    return lastSavedString;
}

char *
stringSaveNoCopy(char *string)
{
    if (!string)
	return NULL;
	
#ifndef USE_HAPTABLE
    lastSavedString = NXHashInsert(stringHash, string);
#else
    lastSavedString =  NXHapInsert(stringHap, string);
#endif
    return lastSavedString;
}

char *
stringSave2(char *s1, char *s2)
{
    char s3[strlen(s1) + strlen(s2) + 1];
    
    strcpy(s3, s1);
    strcat(s3, s2);
    return stringSave(s3);
}

char *
stringSaveN(const char *string, int n)
{
   if (!string)
	return NULL;

    if (string != lastSavedString) {
	char newString[n + 1];
	bcopy(string, newString, n);
	newString[n] = '\0';
#ifndef USE_HAPTABLE
	if (!(lastSavedString = NXHashGet(stringHash, newString))) {
#else
	if (!(lastSavedString = NXHapGet(stringHap, newString))) {
#endif
	    lastSavedString = getNextString(n + 1);
	    bcopy(string, lastSavedString, n);
	    lastSavedString[n] = '\0';
#ifndef USE_HAPTABLE
	    NXHashInsert(stringHash, lastSavedString);
#else
	    NXHapInsert(stringHap, lastSavedString);
#endif
	}
    }
    return lastSavedString;
}

static int pstrcmp(const void *arg1, const void *arg2)
{ return strcmp(*(char **)arg1, *(char **)arg2); }

static void
dumpStrings(char *args, int from_tty)
{
    FILE *stringsFile = fopen(args, "w+");
#ifndef USE_HAPTABLE
    int count = NXCountHashTable(stringHash), i = 0;
    NXHashState state = NXInitHashState(stringHash);
#else
    int count = NXCountHapTable(stringHap), i = 0;
    NXHapState state = NXInitHapState(stringHap);
#endif
    char *strings[sizeof(char *) * count], *string;

#ifndef USE_HAPTABLE
    while (NXNextHashState(stringHash, &state, (void **)&string)) {
#else
    while (NXNextHapState(stringHap, &state, (void **)&string)) {
#endif 0
	strings[i++] = string;
    }
    qsort(strings, count, sizeof(*strings), pstrcmp);
    for (i = 0; i < count; i++) {
	fprintf(stringsFile, "%s\n", strings[i]);
    }
    fclose(stringsFile);
}

static void
dumpStringSize(char *args, int from_tty)
{
#ifndef USE_HAPTABLE
    NXHashState state = NXInitHashState(stringHash);
#else
    NXHapState state = NXInitHapState(stringHap);
#endif
    char *string;
    NXHashState pageState;
    NXHashTable *pageHash = NXCreateHashTable(NXPtrPrototype, 0, NULL);
    FILE *stringsFile = (args && *args) ? fopen(args, "w+") : stdout;
    void *page, *startPage, *endPage;
    int len, stringBytes = 0, stringPages;
#ifndef USE_HAPTABLE
    while (NXNextHashState(stringHash, &state, (void **)&string)) {
#else
    while (NXNextHapState(stringHap, &state, (void **)&string)) {
#endif
	len = strlen(string) + 1;
	startPage = (void *)trunc_page(string);
	endPage = (void *)trunc_page(string + len);
	NXHashInsert(pageHash, startPage);
	if (endPage != startPage)
	    NXHashInsert(pageHash, startPage);
	stringBytes += len;
    }
    stringPages = NXCountHashTable(pageHash);
    fprintf(stringsFile,
            "%d strings.  Total bytes: %d. Total pages: %d (%d bytes)\n", 
#ifndef USE_HAPTABLE
	    NXCountHashTable(stringHash), stringBytes, 
#else
	    NXCountHapTable(stringHap), stringBytes, 
#endif USE_HAPTABLE
	    stringPages, stringPages * vm_page_size);
    pageState = NXInitHashState(pageHash);
    while (NXNextHashState(pageHash, &pageState, &page))
	fprintf(stringsFile, "%p\n", page);
    if (args && *args)
	fclose(stringsFile);
    NXFreeHashTable(pageHash);
}

void
_initialize_string()
{
    static BOOL initialized = NO;
    if (!initialized) {
#ifndef USE_HAPTABLE
	stringHashZone = NXCreateZone(vm_page_size, vm_page_size, YES);
	NXNameZone(stringHashZone, "StringHashZone");
	stringHash = NXCreateHashTableFromZone(NXStrPrototype, 0, NULL, stringHashZone);
#else
	stringHapZone = NXCreateZone(vm_page_size, vm_page_size, YES);
	NXNameZone(stringHapZone, "StringHapZone");
	stringHap = NXCreateHapTableFromZone(NXStrValueHapPrototype, 0, stringHapZone);
#endif 
	initialized = YES;
    }
}
	
void
memory_error (status, memaddr)
     int status;
     CORE_ADDR memaddr;
{

  if (status == EIO)
    {
      /* Actually, address between memaddr and memaddr + len
	 was out of bounds. */
      error ("Cannot access memory: address 0x%x out of bounds.", memaddr);
    }
  else
    {
      if (status >= sys_nerr || status < 0)
	error ("Error accessing memory address 0x%x: unknown error (%d).",
	       memaddr, status);
      else
	error ("Error accessing memory address 0x%x: %s.",
	       memaddr, sys_errlist[status]);
    }
}

/* Same as target_read_memory, but report an error if can't read.  */
void
read_memory (memaddr, myaddr, len)
     CORE_ADDR memaddr;
     char *myaddr;
     int len;
{
  int status;
  status = target_read_memory (memaddr, myaddr, len);
  if (status != 0)
    memory_error (status, memaddr);
}

/* Same as target_write_memory, but report an error if can't write.  */
void
write_memory (memaddr, myaddr, len)
     CORE_ADDR memaddr;
     char *myaddr;
     int len;
{
  int status;

  status = target_write_memory (memaddr, myaddr, len);
  if (status != 0)
    memory_error (status, memaddr);
}

/* Read an integer from debugged memory, given address and number of bytes.  */

long
read_memory_integer (memaddr, len)
     CORE_ADDR memaddr;
     int len;
{
  char cbuf;
  short sbuf;
  int ibuf;
  long lbuf;

  if (len == sizeof (char))
    {
      target_read_memory (memaddr, &cbuf, len);
      return cbuf;
    }
  if (len == sizeof (short))
    {
      target_read_memory (memaddr, (char *)&sbuf, len);
      SWAP_TARGET_AND_HOST (&sbuf, sizeof (short));
      return sbuf;
    }
  if (len == sizeof (int))
    {
      target_read_memory (memaddr, (char *)&ibuf, len);
      SWAP_TARGET_AND_HOST (&ibuf, sizeof (int));
      return ibuf;
    }
  if (len == sizeof (lbuf))
    {
      target_read_memory (memaddr, (char *)&lbuf, len);
      SWAP_TARGET_AND_HOST (&lbuf, sizeof (lbuf));
      return lbuf;
    }
  error ("Cannot handle integers of %d bytes.", len);
  return -1;	/* for lint */
}

int debugPrintf(const char *fmt, ...)
{
    va_list ap;
    if (debugPrint) {
	int ret;
	va_start(ap, fmt);
	ret = vprintf(fmt, ap);
	va_end(ap);
	return ret;
    } else
	return 0;
}

void validateRegister(int regno)
{
    int i;
    extern char register_valid[];
    if (regno == -1) {
	for (i = 0; i < NUM_REGS; i++) {
	    if (!register_valid[i])
		fetch_inferior_registers(i);
	}
    } else if (!register_valid[regno])
	fetch_inferior_registers(regno);
}
    
static int profInited = 0;

static void startProfiling(char *args, int from_tty)
{   
    if (profInited)
	moncontrol(1);
    else {
	moninit();
	profInited = 1;
    }
}

static void stopProfiling(char *args, int from_tty)
{
    if (args && *args)
	monoutput(args);
    else
	monoutput("gmon.out");
    moncontrol(0);
}

void 
_initialize_next()
{
    _initialize_maint_cmds();
    prologueMap = NXCreateMapTable(NXPtrValueMapPrototype, 0);
    add_com("start-profile", class_obscure, startProfiling,
          "Begin profiling.");

    add_com("stop-profile", class_obscure, stopProfiling,
          "End profiling and dump gmon info into [FILE].");

    add_com("end", class_breakpoint, end_command,
            "Execute until end of current function.");
    add_com ("opath-alias", class_obscure, opath_alias_command,
	    "Add path alias for lazy symbol lookup from .o file. OLDPATH=NEWPATH");
    add_com_alias ("opath", "opath-alias", class_obscure, 1);
    add_com ("opath-unalias", class_obscure, opath_unalias_command,
	    "Delete path alias for symbol lookup from .o file. OLDPATH");
    add_cmd ("strings", class_maintenance, dumpStrings,
	     "Print dump of all strings to OUTFILE.",
	     &maintenanceprintlist);
    add_cmd ("stringsize", class_maintenance, dumpStringSize,
	     "Print size of strings.",
	     &maintenanceprintlist);
    add_show_from_set(
      add_set_cmd("debug-print", class_obscure, var_boolean, 
                (char *)&debugPrint,
                "Set if printing debugger debug statements.",
		&setlist),
      &showlist);		
    add_show_from_set(
      add_set_cmd("force_cplusplus", class_obscure, var_boolean, 
                (char *)&force_cplusplus,
                "Set if you know better than the debugger about C++",
		&setlist),
      &showlist);		
    gdb_task = task_self();
    gdb_thread = cthread_self();

}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.