This is loadSymbols.m in view mode; [Download] [Up]
#import "gdb.h" #import <mach-o/rld_state.h> #import <stdlib.h> #import <streams/streams.h> #import "loadSymbols.h" #import "objfiles.h" #import "SegmentManagerThreads.h" static int *nLoadedAddress; static struct rld_loaded_state **loadedAddress; CORE_ADDR changedAddress; static LoadInfo *loaded = NULL; static int nLoaded = 0, nAlloced = 0; static int loadedInited = 0; static LoadInfo *staticLoaded; static int doLoadSymbols = 1; static int doLoadBreakpoints = 1; int baseFileLoaded = 0; extern RegionManager *regionManager; #define INVALID_ADDRESS ((CORE_ADDR)-1) static void removeBreakpoints(CORE_ADDR start, CORE_ADDR end) { invalidate_breakpoints_between(start, end); } static void * addressOfSymbol(char *name) { struct minimal_symbol *minSym = lookup_minimal_symbol(name, NULL, NULL); if (!minSym) error("Couldn't find symbol for %s.", name); return (void *) SYMBOL_VALUE_ADDRESS(minSym); } const static char breakpoint_insn[] = BREAKPOINT; static char oldBreakpointData[sizeof(breakpoint_insn) / sizeof(*breakpoint_insn)]; void insertLoadBreakpoint() { if (loadedInited) { [regionManager getDataAt: (void *)changedAddress for: sizeof(breakpoint_insn) into: (void *)oldBreakpointData]; [regionManager putDataAt: (void *)changedAddress for: sizeof(breakpoint_insn) from: (void *)breakpoint_insn]; } } void removeLoadBreakpoint() { if (loadedInited) { [regionManager putDataAt: (void *)changedAddress for: sizeof(breakpoint_insn) from: (void *)oldBreakpointData]; } } static char entryBreakpointData[sizeof breakpoint_insn]; CORE_ADDR entryPointAddress = INVALID_ADDRESS; static enum { STATE_INIT, STATE_INSERTED, STATE_REMOVED, STATE_DONE } entryBreakpointState = STATE_INIT; static CORE_ADDR findEntryPoint() { extern struct objfile *object_files; struct objfile *objfile; SegmentManager *manager; ThreadInfo *threads; char *IReallyDontCare; int numthreads; for (objfile = object_files; objfile; objfile = objfile->next) { manager = objfile->manager; numthreads = [manager numThreads]; if (numthreads) { if (numthreads > 1) /* Should never happen, in theory */ printf("Executable file %s contains more than 1 LC_UNIXTHREAD/LC_THREAD command.", objfile->name ); threads = [manager threadInfos]; return getThreadPCAndNameFromState(THREADINFO_PC_STATE(*threads), &IReallyDontCare); } } return INVALID_ADDRESS; } insertEntryPointBreakPoint () { if (entryBreakpointState == STATE_DONE) return; if (entryPointAddress == INVALID_ADDRESS) entryPointAddress = findEntryPoint(); if (entryPointAddress == INVALID_ADDRESS) entryPointAddress = (CORE_ADDR)addressOfSymbol("start"); if (entryBreakpointState == STATE_INIT) { [regionManager getDataAt: (void *)entryPointAddress for: sizeof(breakpoint_insn) into: (void *)entryBreakpointData]; } if (entryBreakpointState == STATE_INIT || entryBreakpointState == STATE_REMOVED) { [regionManager putDataAt: (void *)entryPointAddress for: sizeof(breakpoint_insn) from: (void *)breakpoint_insn]; } if (entryBreakpointState == STATE_INIT) maybeAddDyld (); entryBreakpointState = STATE_INSERTED; } removeEntryPointBreakPoint (int done) { if (entryBreakpointState == STATE_INSERTED) { [regionManager putDataAt:(void*)entryPointAddress for: sizeof (breakpoint_insn) from:(void*) entryBreakpointData]; if (done) { entryBreakpointState = STATE_DONE; } else entryBreakpointState = STATE_REMOVED; } } extern void restore_inferior_status_after_error (struct inferior_status*); subscribeDyldEvents () { extern port_t gdb_dyld_port; extern port_set_name_t gdb_ports; struct inferior_status inf_status; struct cleanup *old_chain; kern_return_t ret; /* No need to save current selected frame info, since this routine is * called only when the inferior executes its first instruction, or upon * attaching to the inferior. In either case, there is no previously * selected frame. */ save_inferior_status (&inf_status, 0); old_chain = make_cleanup (restore_inferior_status_after_error, &inf_status); if (gdb_dyld_port == PORT_NULL) { /* MVS: dyld port needs to be opened and closed for each inferior pid */ /* Otherwise, detach does not work (inferior hangs on this port) */ mach_call ( port_allocate (task_self (), &gdb_dyld_port), "port_allocate", "subscribeDyldEvents"); mach_call( port_set_add(task_self(), gdb_ports, gdb_dyld_port), "port_set_add", "subscribeDyldEvents"); } ret = _dyld_debug_add_event_subscriber(inferior_task, 2000, 2000, 0, gdb_dyld_port); discard_cleanups (old_chain); restore_inferior_status(&inf_status); if (ret == KERN_SUCCESS) drainDyldEvents (); } void initLoaded() { if (!lookup_minimal_symbol(RLD_NLOADED_STATES, NULL, NULL)) { // printf("Can't find dynamic state in executable.\n"); return; } nLoadedAddress = addressOfSymbol(RLD_NLOADED_STATES); loadedAddress = addressOfSymbol(RLD_LOADED_STATE); changedAddress = (CORE_ADDR)addressOfSymbol(RLD_LOADED_STATE_CHANGED); loadedInited = 1; entryBreakpointState = STATE_INIT; entryPointAddress = INVALID_ADDRESS; } static unsigned long getLastStateHeader(unsigned long size, unsigned long header_size) { staticLoaded->sizeWithSymbols = size; return (unsigned long)staticLoaded->headerAddr; } BOOL loadSymbolsForInfo(LoadInfo *loadInfo, char **theNames) { unsigned long maxAddr; struct load_command *cmd; int i; SegmentManager *manager; NXStream *errorStream = NXOpenFile(fileno(stderr), NX_WRITEONLY); staticLoaded = loadInfo; if (!baseFileLoaded) { rld_load_basefile(NULL, get_exec_file(YES)); baseFileLoaded = YES; } rld_address_func(getLastStateHeader); if (rld_load(errorStream, &loadInfo->header, theNames, RLD_DEBUG_OUTPUT_FILENAME) == 1) { staticLoaded = NULL; maxAddr = (unsigned long)loadInfo->headerAddr; for (cmd = (struct load_command *)(loadInfo->header + 1), i = 0; i < loadInfo->header->ncmds; ((void *)cmd) += cmd->cmdsize, i++) { if (cmd->cmd == LC_SEGMENT) { struct segment_command *segCmd = (struct segment_command *)cmd; unsigned long topAddr = segCmd->vmaddr + segCmd->vmsize; if (topAddr > maxAddr) maxAddr = topAddr; } } loadInfo->sizeWithoutSymbols = maxAddr - (unsigned long)loadInfo->headerAddr; manager = [SegmentManager newHeader: loadInfo->header withSize: loadInfo->sizeWithSymbols]; addExecManager(manager); loadInfo->objfile = (void *)symfile_add(manager, 0, 0, 0, 0, 0); loadInfo->loadOK = YES; NXClose(errorStream); return 0; } else { NXFlush(errorStream); NXClose(errorStream); printf("gdb: error loading symbols from"); for (i = 0; theNames[i]; i++) { if (i > 0) printf(","); printf(" %s", theNames[i]); } printf(".\n"); loadInfo->loadOK = NO; return 1; } } static BOOL loadSymbols(struct rld_loaded_state *state, LoadInfo *loadInfo) { char **names, **theNames; int i; loadInfo->headerAddr = state->header_addr; loadInfo->names = state->object_filenames; names = [regionManager pointerFor: state->object_filenames withSize: sizeof(char *) * state->nobject_filenames]; theNames = alloca(sizeof(char *) * (state->nobject_filenames + 1)); for (i = 0; i < state->nobject_filenames; i++) theNames[i] = WARPSTRING(names[i]); theNames[state->nobject_filenames] = NULL; return loadSymbolsForInfo(loadInfo, theNames); } static void loadStatesUntil(int newNLoaded) { struct rld_loaded_state *loadedState; struct rld_loaded_state **myLoadedAddress; if (loaded) { if (newNLoaded > nAlloced) { nAlloced *= 2; loaded = realloc(loaded, sizeof(*loaded) * nAlloced); } } else { nAlloced = 10; loaded = malloc(sizeof(*loaded) * nAlloced); } if ((myLoadedAddress = WARP(loadedAddress)) && (loadedState = [regionManager pointerFor: *myLoadedAddress withSize: sizeof(*loadedState) * newNLoaded])) { for (; (nLoaded < newNLoaded); nLoaded++) { loadSymbols(loadedState + nLoaded, loaded + nLoaded); } if (doLoadBreakpoints) { // extern void resolve_unresolved_breakpoints(); // resolve_unresolved_breakpoints(); } } else error("Problem getting at dynamic loading information."); } void addLoadedObjectModule (struct objfile *obj) { LoadInfo *load; if (loaded) { if (nLoaded == nAlloced) { nAlloced *= 2; loaded = realloc(loaded, sizeof(*loaded) * nAlloced); } } else { nAlloced = 10; loaded = malloc(sizeof(*loaded) * nAlloced); } load = loaded + nLoaded; nLoaded += 1; load->objfile = obj; load->headerAddr = [(id) obj->manager getMinimumAddressForSegment:"__TEXT"]; load->sizeWithoutSymbols = [obj->manager getMaximumTextAddress] - (unsigned) load->headerAddr; load->loadOK = YES; } static void unloadSymbols(LoadInfo *loaded) { if (loaded->loadOK) { SegmentManager *manager; removeBreakpoints((CORE_ADDR)loaded->headerAddr, (CORE_ADDR)(loaded->headerAddr + loaded->sizeWithoutSymbols)); manager = loaded->objfile->manager; free_objfile(loaded->objfile); removeExecManager(manager); rld_unload(NULL); } } void unloadStatesFrom(int newNLoaded) { while (nLoaded > newNLoaded) { nLoaded--; unloadSymbols(loaded + nLoaded); } } void reallyGetLoadedSymbols() { int newNLoaded; int *myNLoadedAddress; if (!inferior_task) error("Program must be running to load the dynamic symbols."); if (loadedInited) { myNLoadedAddress = WARP(nLoadedAddress); if (myNLoadedAddress) { newNLoaded = *myNLoadedAddress; if (newNLoaded > nLoaded) { loadStatesUntil(newNLoaded); } else if (newNLoaded < nLoaded) { unloadStatesFrom(newNLoaded); } } else { error("Problem getting at dynamic loading information."); } } } void getLoadedSymbols() { if (doLoadSymbols) reallyGetLoadedSymbols(); } void _initialize_loadSymbols() { add_com("load-symbols", no_class, &reallyGetLoadedSymbols, "Talk to rld and load in all symbols that rld knows about."); add_show_from_set( add_set_cmd("autoload-symbols", no_class, var_boolean, (char *) &doLoadSymbols, "Set automatic loading of symbols of dynamic code.", &setlist), &showlist); add_show_from_set( add_set_cmd("autoload-breakpoints", no_class, var_boolean, (char *) &doLoadBreakpoints, "Set automatic reseting of breakpoints in dynamic code.", &setlist), &showlist); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.