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" gdb.h imports this already: MVS */ #import "objfiles.h" #include <errno.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(libCmd, originalName) 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(header) struct mach_header *header; { return (header->filetype == MH_EXECUTE) || (header->filetype == MH_OBJECT) || (header->filetype == MH_PRELOAD); } void symbolFileAddShlibs(manager) 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(manager) 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(val, pst) unsigned int val; struct partial_symtab *pst; { if (val == 0 || 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(arg1, arg2) const void *arg1, *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(objfile) 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) && (SYMBOL_VALUE_ADDRESS(minSym) != miscPSymtab->val); minSym++) ; if (minSym < endOfMinSyms) { MSYMBOL_INFO(minSym) = (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(ind) 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(function, start, end) CORE_ADDR function, start, 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; } #ifdef NeXT /* temp kludge: name conflict with enum in defs.h */ #define end_command End_Command #endif /* NeXT */ static void end_command(args, from_tty) 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); if (block != 0) /* MVS: don't know why it fails, but it does... */ function = BLOCK_START(block); if (block == 0 || function == 0) error("end: internal error, can't fulfill request"); 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(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(args, from_tty) char *args; int from_tty; { struct cleanup *cleanups; lock_execute_command(YES); cleanups = make_cleanup(lock_execute_command, NO); execute_command(args, from_tty); do_cleanups(cleanups); } struct opaths { char *old, *new; struct opaths *next; } *opaths; void opath_alias_command(paths, from_tty) 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 (path, from_tty) 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(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(string) const char *string; { if (!string) return NULL; #ifndef USE_HAPTABLE if ((string != lastSavedString) && !(lastSavedString = NXHashGet(stringHash, string))) #else if ((string != lastSavedString) && !(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(string) char *string; { if (!string) return NULL; #ifndef USE_HAPTABLE lastSavedString = NXHashInsert(stringHash, string); #else lastSavedString = NXHapInsert(stringHap, string); #endif return lastSavedString; } char * stringSave2(s1, s2) char *s1, *s2; { char s3[strlen(s1) + strlen(s2) + 1]; /* CAUTION: gcc extension! */ strcpy(s3, s1); strcat(s3, s2); return stringSave(s3); } char * stringSaveN(string, n) 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(arg1, arg2) const void *arg1; const void *arg2; { return strcmp(*(char **)arg1, *(char **)arg2); } static void dumpStrings(args, from_tty) 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(args, from_tty) 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. */ LONGEST read_memory_integer (memaddr, len) CORE_ADDR memaddr; int len; { char buf[sizeof (LONGEST)]; read_memory (memaddr, buf, len); return extract_signed_integer (buf, len); } unsigned LONGEST read_memory_unsigned_integer (memaddr, len) CORE_ADDR memaddr; int len; { char buf[sizeof (unsigned LONGEST)]; read_memory (memaddr, buf, len); return extract_unsigned_integer (buf, len); } /* mread -- read memory (unsigned) and apply a bitmask */ unsigned long mread(addr, len, mask) CORE_ADDR addr; unsigned long len, mask; { long ret = read_memory_unsigned_integer (addr, len); if (mask) ret &= mask; return ret; } 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(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(args, from_tty) char *args; int from_tty; { if (profInited) moncontrol(1); else { moninit(); profInited = 1; } } static void stopProfiling(args, from_tty) char *args; int from_tty; { if (args && *args) monoutput(args); else monoutput("gmon.out"); moncontrol(0); } /* * symbols_changed_hook: * update anything needful when new symbols have been * loaded, eg. by the addition of a new shared library. * I'm sure there's a better, more GNU-ish way to do this. MVS */ void symbols_changed_hook (struct objfile * obj) { find_objc_msgsend (); } 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.