This is MachOView.m in view mode; [Download] [Up]
#import <MachOView.h> /* $Log: MachOView.m,v $ Revision 1.18 94/05/29 15:00:14 ediger zero out a memory allocation to make it clear it's unused Revision 1.17 94/05/28 16:17:55 ediger finally got section names to draw acceptably. Revision 1.16 94/05/26 21:21:06 ediger correct address bracket zooming, hi and lo address bracket checking Revision 1.15 94/05/23 20:32:13 ediger lot's o' stuff to do address bracket zoom-in Revision 1.14 94/05/17 23:09:48 ediger support for stacking of zoomed address ranges, changed types of some instance vars from id to pointer to that kind of object. Revision 1.13 94/05/10 22:41:07 ediger support for displaying a "zooming box" by mouse drag Revision 1.12 94/05/04 11:19:58 ediger rearrange drawSelf:: to be a bit more modular Revision 1.10 94/05/01 17:32:57 ediger efficiency improvements Revision 1.9 94/02/07 21:37:17 ediger Use of memory-mapped file object to manage file mapping, add display of segment names and use of matrix of buttons for choices of what to display. Revision 1.7 94/01/30 16:27:34 ediger mostly correct address spacing Revision 1.6 94/01/01 23:02:22 ediger broke address label spacing calcs into separate method. Revision 1.5 93/12/31 17:32:28 ediger better address label spacing Revision 1.3 93/12/30 19:01:37 ediger support for showing upper and lower addresses of memory mapped segments. Revision 1.2 93/12/19 14:31:43 ediger corrected scaling and inclusion of mapped segments of library files Revision 1.1 93/12/19 12:57:04 ediger Initial revision */ @implementation MachOView static char rcsident[] = "$Id: MachOView.m,v 1.18 94/05/29 15:00:14 ediger Exp Locker: ediger $"; #undef DEBUG #ifdef DEBUG #define D(c) c #define ENTER(m) fprintf(stderr, "enter %s\n", m); #define EXIT(m) fprintf(stderr, "exit %s\n", m); #else #define D(c) #define ENTER(m) #define EXIT(m) #endif //M+ -findSizes // PURPOSE: // Sort through the addresses of the mapped segments in the Mach-O file // to be represented, determining the high address, low address, and // the number of bytes used in the address space. // // EDITORIAL: // Should only be called after using MachOFile instance var to // open or re-open the Mach-O file being represented. //M- - findSizes { int iSegments, iCC; unsigned long ulBaseAddr, ulUpperAddr; char bvBuf[64]; ENTER("- findSizes"); loAddr = (unsigned long)-1; /* cheat */ sumAddr = hiAddr = 0; iSegments = [theFile mappedSegments]; for (iCC = 0; iCC < iSegments; ++iCC) { id oSegment = [theFile mappedSegment:iCC]; ulBaseAddr = [oSegment getBaseAddress]; if (loAddr > ulBaseAddr) loAddr = ulBaseAddr; ulUpperAddr = [oSegment getUpperAddress]; if (hiAddr < ulUpperAddr) hiAddr = ulUpperAddr; sumAddr += (ulUpperAddr - ulBaseAddr); } sprintf(bvBuf, "0x%x", loAddr); [minAddress setStringValue:bvBuf]; sprintf(bvBuf, "0x%x", hiAddr); [maxAddress setStringValue:bvBuf]; EXIT("- findSizes"); return self; } //M+ -(char *)fileType //M- - (char *)fileType { return [theFile fileType]; } //M+ -openFileNamed:(char *)fileName // //M- - openFileNamed:(char *)fileName { ENTER("- openFileNamed:"); assert(NULL != fileName); [self freeInternals]; currentFileName = strcpy(malloc(strlen(fileName) + 1), fileName); mappedFile = [[[MappedFile alloc] init] filename:currentFileName]; if (mappedFile == NULL || [mappedFile map] == FALSE) { [cpuType setStringValue:"Problem opening"]; [cpuSubtype setStringValue:currentFileName]; } else { theFile = [[[MachOFile alloc]init] fillFromAddress:[mappedFile address]]; if (NULL == theFile) { [cpuType setStringValue:"Not a"]; [cpuSubtype setStringValue:"Mach-O file"]; } else { int iSegments = [theFile mappedSegments]; addressMap = (struct addressMapping *)malloc( iSegments * sizeof(struct addressMapping)); bzero(addressMap, iSegments * sizeof(struct addressMapping)); [cpuType setStringValue:[theFile cpuType]]; [cpuSubtype setStringValue:[theFile cpuSubtype]]; [[self findSizes] display]; } } EXIT("- openFileNamed:"); return self; } //M+ -toggleScaling:sender // Action called by clicking on a button. Changes the "toScale" instance // variable, and calls -display, to reflect the change. //M- - toggleScaling:sender { if (toScale) { toScale = FALSE; showSectionNames = FALSE; [showSectionsButton setEnabled:NO]; [showSectionsButton setIntValue:0]; } else { toScale = TRUE; [showSectionsButton setEnabled:YES]; [showSectionsButton setIntValue:0]; } [self display]; return self; } //M+ -toggleAddresses:sender // Action called by clicking on a button. Changes the "showAddresses" // instance variable, and calls -display, to reflect the change. //M- - toggleAddresses:sender { if (showAddresses) showAddresses = FALSE; else showAddresses = TRUE; [self display]; return self; } //M+ -toggleNames:sender // Action called by clicking on a button. Changes the "showNames" // instance variable, and calls -display, to reflect the change. //M- - toggleNames:sender { if (showNames) showNames = FALSE; else showNames = TRUE; [self display]; return self; } //M+ -toggleThreads:sender // Action called by clicking on a button. Changes the "showThreads" // instance variable, and calls -display, to reflect the change. //M- - toggleThreads:sender { if (showThreads) showThreads = FALSE; else showThreads = TRUE; [self display]; return self; } //M+ -toggleSections:sender // Action called by clicking on a button. Changes the "showSectionNames" // instance variable, and calls -display, to reflect the change. //M- - toggleSections:sender { int iSegments, iCC; if (showSectionNames) showSectionNames = FALSE; else showSectionNames = TRUE; iSegments = [theFile mappedSegments]; for (iCC = iSegments - 1; iCC > -1; --iCC) { int i; SegmentCommand *oSegment = [theFile mappedSegment:iCC]; int iSection = [oSegment numberOfSections]; struct section *spSection = [oSegment getSection:0]; if (iSection > 0) { if (addressMap[iCC].sectionMap == NULL) addressMap[iCC].sectionMap = (struct sectionNameMapping *)malloc( iSection*sizeof(struct sectionNameMapping)); assert(addressMap[iCC].sectionMap != NULL); for (i = 0; i < iSection; ++i) { addressMap[iCC].sectionMap[i].sectionName = spSection[i].sectname; addressMap[iCC].sectionMap[i].sectionAddress = spSection[i].addr; } } else addressMap[iCC].sectionMap = NULL; } [self display]; return self; } //M+ -toggleLibraries:sender // PURPOSE: // Action called by clicking on a button. Changes the "showLibraries" // instance variable, and calls -display, to reflect the change. // EDITORIAL: // Somewhat more elaborate than the other -toggle* methods, since the // Mach-O file object instance variable gets completely redone. This // may be a case of bad design of the MachOFile object percolating up // to here. //M- - toggleLibraries:sender; { if (theFile != NULL) [theFile free]; theFile = [[MachOFile alloc] init]; if (NULL != addressMap) { int iSegments = [theFile mappedSegments]; while (--iSegments > -1) if (addressMap[iSegments].sectionMap) free(addressMap[iSegments].sectionMap); free(addressMap); addressMap = NULL; } if (showLibraries) { showLibraries = FALSE; [theFile unconsiderMappedFiles]; } else { showLibraries = TRUE; [theFile considerMappedFiles]; } [theFile fillFromAddress:[mappedFile address]]; addressMap = (struct addressMapping *)malloc( [theFile mappedSegments] * sizeof(struct addressMapping)); bzero(addressMap, [theFile mappedSegments] * sizeof(struct addressMapping)); // since the MachOFile object has been redone, zoom state is meaningless. if (NULL != zoomStack) { void *vp; while ((vp = [zoomStack pop]) != NULL) free(vp); } [unzoomButton setEnabled:NO]; [zoomButton setEnabled:NO]; [[self findSizes] display]; return self; } //M+ -windowWillClose:sender // PURPOSE: // Ditch any memory-consuming instance vars when the window closes. // EDITORIAL: // one of the Window delegate methods //M- - windowWillClose:sender { ENTER("- windowWillClose:"); [self freeInternals]; [zoomStack free]; EXIT("- windowWillClose:"); return self; } //M+ -rescale // PURPOSE: // calculate the scaling instance vars //M- - rescale { float ht; ENTER("- rescale"); ht = NX_HEIGHT(&bounds) - 25.0; scaleSlope = ht/(float)(hiAddr - loAddr); scaleYintercept = 5.0 - scaleSlope*(float)loAddr; smashedSlope = ht/(float)sumAddr; smashedYintercept = 0.0; EXIT("- rescale"); return self; } //M+ -initFrame:(const NXRect *)frameRect // PURPOSE: // Set a bunch of instance variables to some sensible values. // // EDITORIAL: // Override of a View method //M- - initFrame:(const NXRect *)frameRect { ENTER("- initFrame:"); [super initFrame:frameRect]; toScale = TRUE; showLibraries = FALSE; showAddresses = TRUE; showNames = TRUE; showThreads = TRUE; showSectionNames = FALSE; currentFileName = NULL; addressMap = NULL; mappedFile = NULL; theFile = NULL; zoomStack = [[Queue alloc] init]; theFont = [Font newFont:"Courier" size:(float)(LABEL_HT - LABEL_LEADING) matrix:NX_IDENTITYMATRIX]; EXIT("- initFrame:"); return self; } //M+ -drawSelf:(NXRect *)rects :(int)rectCount // // EDITORIAL: // Override of a View method. // This is way too complicated. //M- - drawSelf:(NXRect *)rects :(int)rectCount { int iSegments, iCC; float xCoord, yCoord, yLast; ENTER("- drawSelf::"); [self rescale]; // make background white and lines black PSsetgray(NX_WHITE); NXRectFill(&bounds); PSsetgray(NX_BLACK); NXFrameRect(&bounds); PSsetgray(NX_BLACK); PSnewpath(); PSsetlinewidth(LINE_WDTH); [theFont set]; iSegments = [theFile mappedSegments]; if (iSegments == 0) return self; /* stagger the lines representing memory allocations */ xCoord = NX_WIDTH(&bounds)/2.0 - ((float)iSegments/2.0)*LINE_STAGGER; yCoord = VERT_MARGIN; yLast = [[theFile mappedSegment:iSegments - 1] getBaseAddress] - 1.0; /* count down so that the "not to scale" bit works */ for (iCC = iSegments - 1; iCC > -1; --iCC) { id oSegment = [theFile mappedSegment:iCC]; unsigned long ulBaseAddr = [oSegment getBaseAddress]; unsigned long ulUpperAddr = [oSegment getUpperAddress]; if (ulBaseAddr > hiAddr) break; // don't need to check any higher if ( (ulUpperAddr <= hiAddr && ulBaseAddr >= loAddr) || (ulUpperAddr >= loAddr && ulBaseAddr < loAddr) || (ulUpperAddr > hiAddr && ulBaseAddr < hiAddr) ) { addressMap[iCC].baseAddress = (loAddr < ulBaseAddr)?ulBaseAddr:loAddr; addressMap[iCC].endAddress = (hiAddr > ulUpperAddr)?ulUpperAddr:hiAddr; if (showNames) addressMap[iCC].segmentName = [oSegment commandName]; if (toScale) { addressMap[iCC].yCoordBase = (loAddr < ulBaseAddr)? scaleSlope*(float)ulBaseAddr + scaleYintercept : scaleSlope*(float)loAddr + scaleYintercept ; addressMap[iCC].yCoordTop = (hiAddr > ulUpperAddr) ? scaleSlope*(float)ulUpperAddr + scaleYintercept : scaleSlope*(float)hiAddr + scaleYintercept ; PSmoveto(xCoord, addressMap[iCC].yCoordBase); PSlineto(xCoord, addressMap[iCC].yCoordTop); } else { if (ulBaseAddr != yLast) PSmoveto(xCoord, yCoord + SEGMENT_GAP); else PSmoveto(xCoord, yCoord); if (ulBaseAddr != yLast) addressMap[iCC].yCoordBase = yCoord + SEGMENT_GAP; else addressMap[iCC].yCoordBase = yCoord; if (ulUpperAddr <= hiAddr && ulBaseAddr >= loAddr) yCoord += smashedSlope * (float)(ulUpperAddr - ulBaseAddr) + smashedYintercept; else if (ulUpperAddr >= loAddr && ulBaseAddr < loAddr) yCoord += smashedSlope * (float)(ulUpperAddr - loAddr) + smashedYintercept; else if (ulUpperAddr > hiAddr && ulBaseAddr < hiAddr) yCoord += smashedSlope * (float)(hiAddr - ulBaseAddr) + smashedYintercept; PSlineto(xCoord, yCoord); addressMap[iCC].yCoordTop = yCoord; yLast = ulUpperAddr; } /* stagger to the right, on the way up */ xCoord += LINE_STAGGER; } } PSstroke(); if (yLooping) { // draw on the box marking the zooming zone drawBox(sFirstMouseDown.x, sFirstMouseDown.y, sMouseDown.x, sMouseDown.y); } else { [zoomButton setEnabled:NO]; } /* label the ends of each memory segment with its address */ if (TRUE == showAddresses) [self drawAddresses]; /* label the middle of each memory segment with its name */ if (TRUE == showNames) [self drawSegmentNames]; /* draw in little markers for threads program counters */ if (showThreads) [self drawThreads]; if (showSectionNames) [self drawSectionNames]; EXIT("- drawSelf::"); return self; } //M+ -drawThreads //M- - drawThreads { int iCC, iThreadCount = [theFile threads]; int iSegCount = [theFile mappedSegments]; PSsetlinewidth(0.50); for (iCC = 0; iCC < iThreadCount; ++iCC) { float xCoord, yCoord; int iSegNo = [theFile segmentOfThread:iCC]; // iSegNo is -1 if there's no segment containing this thread's PC. // abort(2) causes just this sort of situation. if (iSegNo > -1) { unsigned long ulPCAddr = [[theFile thread:iCC] pc]; if (ulPCAddr >= loAddr && ulPCAddr <= hiAddr) { xCoord = NX_WIDTH(&bounds)/2.0 - ((float)[theFile mappedSegments]/2.0)*(LINE_STAGGER) + (float)(iSegCount - iSegNo) * LINE_STAGGER; yCoord = addressMap[iSegNo].yCoordBase + (addressMap[iSegNo].yCoordTop - addressMap[iSegNo].yCoordBase) * ((float)ulPCAddr - addressMap[iSegNo].baseAddress) / (addressMap[iSegNo].endAddress-addressMap[iSegNo].baseAddress); drawLeftArrowHead(xCoord, yCoord, 8.0); } } } return self; } //M+ -spaceLabels // Figure out the spacing of the address labels // Fills in yCoordBaseLabel and yCoordTopLabel fields such that the // addresses don't overlap, and don't end up out of the MachOView. // yCoordBaseLabel field ends up as -1.0 if it is the same number // as the yCoordTopLabel of the preceding (lower in memory) segment. //M- - spaceLabels { float lastY; float yLastAddress; int iCC, iSegments = [theFile mappedSegments]; lastY = addressMap[iSegments - 1].baseAddress - 20.0; yLastAddress = addressMap[iSegments - 1].yCoordBase - LABEL_HT; for (iCC = iSegments - 1; iCC > -1; --iCC) { if (addressMap[iCC].baseAddress > hiAddr) break; // no need to go any higher if ( (addressMap[iCC].endAddress <= hiAddr && addressMap[iCC].baseAddress >= loAddr) ||(addressMap[iCC].endAddress >= loAddr && addressMap[iCC].baseAddress < loAddr) ||(addressMap[iCC].endAddress > hiAddr && addressMap[iCC].baseAddress < hiAddr) ) { if (addressMap[iCC].baseAddress != lastY) { if (addressMap[iCC].yCoordBase < yLastAddress + LABEL_HT) addressMap[iCC].yCoordBaseLabel = yLastAddress + (LABEL_HT + 2.0); else addressMap[iCC].yCoordBaseLabel=addressMap[iCC].yCoordBase; yLastAddress = addressMap[iCC].yCoordBaseLabel; } else { /* don't need to show this segment's base address */ addressMap[iCC].yCoordBaseLabel = -1.0; } if (addressMap[iCC].yCoordTop < yLastAddress + LABEL_HT) addressMap[iCC].yCoordTopLabel = yLastAddress + (LABEL_HT+2.0); else addressMap[iCC].yCoordTopLabel = addressMap[iCC].yCoordTop; yLastAddress = addressMap[iCC].yCoordTopLabel; lastY = addressMap[iCC].endAddress; } } if (yLastAddress + LABEL_HT > NX_HEIGHT(&bounds)) { yLastAddress = NX_HEIGHT(&bounds) - (LABEL_HT + 2.0); /* try to reshuffle address labels so everything fits */ for (iCC = 0; iCC < iSegments; ++iCC) { if (addressMap[iCC].endAddress < loAddr) break; // no need to go any lower if ( (addressMap[iCC].endAddress <= hiAddr && addressMap[iCC].baseAddress >= loAddr) ||(addressMap[iCC].endAddress >= loAddr && addressMap[iCC].baseAddress < loAddr) ||(addressMap[iCC].endAddress > hiAddr && addressMap[iCC].baseAddress < hiAddr) ) { if (addressMap[iCC].yCoordTopLabel > yLastAddress) { addressMap[iCC].yCoordTopLabel = yLastAddress; yLastAddress -= (LABEL_HT + 2.0); } else if (0.0 > addressMap[iCC].yCoordTopLabel) continue; // this label doesn't show. go to next visible. else break; /* slipped down into a gap */ if (addressMap[iCC].yCoordBaseLabel > yLastAddress) { addressMap[iCC].yCoordBaseLabel = yLastAddress; yLastAddress -= (LABEL_HT + 2.0); } else if (0.0 > addressMap[iCC].yCoordBaseLabel) continue; else break; } } } return self; } //M+ -spaceNames // Figure out the spacing of the segment name labels // Fills in yCoordBaseLabel field such that the // names don't overlap, and don't end up out of the MachOView. // Segment //M- - spaceNames { int iCC, iSegments = [theFile mappedSegments]; float yLastAddress; yLastAddress = addressMap[iSegments - 1].yCoordBase - LABEL_HT; for (iCC = iSegments - 1; iCC > -1; --iCC) { if ( (addressMap[iCC].endAddress <= hiAddr && addressMap[iCC].baseAddress >= loAddr) ||(addressMap[iCC].endAddress >= loAddr && addressMap[iCC].baseAddress < loAddr) ||(addressMap[iCC].endAddress > hiAddr && addressMap[iCC].baseAddress < hiAddr) ) { /* space name across width of view */ addressMap[iCC].nameXcoord = NX_WIDTH(&bounds) - LABEL_MARGIN - [theFont getWidthOf:addressMap[iCC].segmentName]; /* put name in middle of segment vertically */ addressMap[iCC].nameYcoord = (addressMap[iCC].yCoordBase + addressMap[iCC].yCoordTop)/2.0; /* handle overlaps */ if (addressMap[iCC].nameYcoord < yLastAddress + LABEL_HT) addressMap[iCC].nameYcoord = yLastAddress + LABEL_HT; yLastAddress = addressMap[iCC].nameYcoord; } } if (yLastAddress + LABEL_HT > NX_HEIGHT(&bounds)) { yLastAddress = NX_HEIGHT(&bounds) - (LABEL_HT + 2.0); /* try to reshuffle address labels so everything fits */ for (iCC = 0; iCC < iSegments; ++iCC) { if ( (addressMap[iCC].endAddress <= hiAddr && addressMap[iCC].baseAddress >= loAddr) ||(addressMap[iCC].endAddress >= loAddr && addressMap[iCC].baseAddress < loAddr) ||(addressMap[iCC].endAddress > hiAddr && addressMap[iCC].baseAddress < hiAddr) ) { if (addressMap[iCC].nameYcoord > yLastAddress) { addressMap[iCC].nameYcoord = yLastAddress; yLastAddress -= (LABEL_HT + 2.0); } else break; /* slipped down into a gap */ } } } return self; } //M+ -free //M- - free { ENTER("- free"); [self freeInternals]; [zoomStack free]; [super free]; EXIT("- free"); return self; } //M+ - freeInternals //M- - freeInternals { ENTER("- freeInternals"); if (NULL != addressMap) { int iSegments = [theFile mappedSegments]; while (--iSegments > -1) if (addressMap[iSegments].sectionMap) free(addressMap[iSegments].sectionMap); free(addressMap); addressMap = NULL; } if (NULL != currentFileName) { free(currentFileName); currentFileName = NULL; } if (NULL != theFile) { [theFile free]; theFile = NULL; } if (NULL != mappedFile) { [mappedFile free]; mappedFile = NULL; } if (NULL != zoomStack) { // free zoomStack's contents void *vp; while ((vp = [zoomStack pop]) != NULL) free(vp); } EXIT("- freeInternals"); return self; } //M+ -show:sender //M- - show:sender { [theWindow makeKeyAndOrderFront:self]; return self; } //M+ -drawAddresses //M- - drawAddresses { float yCoord, xCoord; int iCC, iSegments; iSegments = [theFile mappedSegments]; /* figure out address label spacing */ [self spaceLabels]; PSnewpath(); PSsetlinewidth(0.50); /* thin lines to each segment */ [theFont set]; yCoord = VERT_MARGIN; xCoord = NX_WIDTH(&bounds)/2.0 - ((float)iSegments/2.0)*(LINE_STAGGER); for (iCC = iSegments - 1; iCC > -1; --iCC) { char bvBuffer[256]; if (addressMap[iCC].baseAddress > hiAddr) break; // no need to go any higher if ( (addressMap[iCC].endAddress <= hiAddr && addressMap[iCC].baseAddress >= loAddr) ||(addressMap[iCC].endAddress >= loAddr && addressMap[iCC].baseAddress < loAddr) ||(addressMap[iCC].endAddress > hiAddr && addressMap[iCC].baseAddress < hiAddr) ) { if (!(addressMap[iCC].yCoordBaseLabel < 0.0)) { sprintf(bvBuffer, "0x%x", (unsigned int)addressMap[iCC].baseAddress); drawLabel(LABEL_MARGIN, addressMap[iCC].yCoordBaseLabel, bvBuffer, xCoord - (LINE_STAGGER - LABEL_MARGIN), addressMap[iCC].yCoordBase); } sprintf(bvBuffer, "0x%x", (unsigned int)addressMap[iCC].endAddress); drawLabel(LABEL_MARGIN, addressMap[iCC].yCoordTopLabel, bvBuffer, xCoord - (LINE_STAGGER - LABEL_MARGIN), addressMap[iCC].yCoordTop); xCoord += LINE_STAGGER; } } PSstroke(); return self; } //M+ -drawSegmentNames //M- - drawSegmentNames { float xCoord; int iCC, iSegments; if (FALSE == showAddresses) [self spaceLabels]; [self spaceNames]; PSnewpath(); PSsetlinewidth(0.50); [theFont set]; iSegments = [theFile mappedSegments]; xCoord = NX_WIDTH(&bounds)/2.0 - ((float)iSegments/2.0)*(LINE_STAGGER) + 5.0; for (iCC = iSegments - 1; iCC > -1; --iCC) { if (addressMap[iCC].baseAddress > hiAddr) break; // no need to go any higher if ( (addressMap[iCC].endAddress <= hiAddr && addressMap[iCC].baseAddress >= loAddr) ||(addressMap[iCC].endAddress >= loAddr && addressMap[iCC].baseAddress < loAddr) ||(addressMap[iCC].endAddress > hiAddr && addressMap[iCC].baseAddress < hiAddr) ) { xCoord += LINE_STAGGER; PSmoveto( xCoord, (addressMap[iCC].yCoordBase + addressMap[iCC].yCoordTop)/2.0); PSlineto( addressMap[iCC].nameXcoord - 10.0, addressMap[iCC].nameYcoord); PSmoveto(addressMap[iCC].nameXcoord, addressMap[iCC].nameYcoord); PSshow(addressMap[iCC].segmentName); } } PSstroke(); return self; } //M+ -spaceSectionNames //M- - spaceSectionNames { int iCC, iSegments; float yLastAddress; iSegments = [theFile mappedSegments]; yLastAddress = addressMap[iSegments - 1].yCoordBase - LABEL_HT; for (iCC = iSegments - 1; iCC > -1; --iCC) { if (addressMap[iCC].baseAddress > hiAddr) break; // no need to go any higher if ( (addressMap[iCC].endAddress <= hiAddr && addressMap[iCC].baseAddress >= loAddr) ||(addressMap[iCC].endAddress >= loAddr && addressMap[iCC].baseAddress < loAddr) ||(addressMap[iCC].endAddress > hiAddr && addressMap[iCC].baseAddress < hiAddr) ) { SegmentCommand *oSegment = [theFile mappedSegment:iCC]; int iSection = [oSegment numberOfSections]; if (iSection > 0 && addressMap[iCC].sectionMap != NULL) { int i; for (i = 0; i < iSection; ++i) { if( (addressMap[iCC].sectionMap[i].sectionAddress <= hiAddr) && (addressMap[iCC].sectionMap[i].sectionAddress >= loAddr) ) { if (toScale) { addressMap[iCC].sectionMap[i].nameYcoord = scaleSlope*(float)addressMap[iCC].sectionMap[i].sectionAddress + scaleYintercept; } else { addressMap[iCC].sectionMap[i].nameYcoord = smashedSlope*(float)addressMap[iCC].sectionMap[i].sectionAddress + smashedYintercept; } if (addressMap[iCC].sectionMap[i].nameYcoord <= yLastAddress+LABEL_HT) addressMap[iCC].sectionMap[i].nameYcoord = yLastAddress + LABEL_HT; yLastAddress = addressMap[iCC].sectionMap[i].nameYcoord; } } } } } return self; } //M+ -drawSectionNames //M- - drawSectionNames { float xCoord; int iCC, iSegments; [self spaceSectionNames]; PSnewpath(); PSsetlinewidth(0.50); [theFont set]; iSegments = [theFile mappedSegments]; xCoord = NX_WIDTH(&bounds)/2.0 - ((float)iSegments/2.0)*(LINE_STAGGER) + 5.0; for (iCC = iSegments - 1; iCC > -1; --iCC) { if (addressMap[iCC].baseAddress > hiAddr) break; // no need to go any higher if ( (addressMap[iCC].endAddress <= hiAddr && addressMap[iCC].baseAddress >= loAddr) ||(addressMap[iCC].endAddress >= loAddr && addressMap[iCC].baseAddress < loAddr) ||(addressMap[iCC].endAddress > hiAddr && addressMap[iCC].baseAddress < hiAddr) ) { SegmentCommand *oSegment = [theFile mappedSegment:iCC]; int iSection = [oSegment numberOfSections]; if (iSection > 0 && addressMap[iCC].sectionMap != NULL) { int i; for (i = 0; i < iSection; ++i) { if( (addressMap[iCC].sectionMap[i].sectionAddress <= hiAddr) &&(addressMap[iCC].sectionMap[i].sectionAddress >= loAddr) ) { float yCoord; if (toScale) { yCoord = scaleSlope*(float)addressMap[iCC].sectionMap[i].sectionAddress + scaleYintercept; } else { yCoord = smashedSlope*(float)addressMap[iCC].sectionMap[i].sectionAddress + smashedYintercept; } PSmoveto(xCoord, yCoord); PSlineto(xCoord + 10.0, addressMap[iCC].sectionMap[i].nameYcoord); PSmoveto(xCoord + 14.0, addressMap[iCC].sectionMap[i].nameYcoord); PSshow(addressMap[iCC].sectionMap[i].sectionName); } } } xCoord += LINE_STAGGER; } } PSstroke(); return self; } //M+ - mouseDown:(NXEvent *)spTheEvent // PURPOSE: // draw a box following the user's mouse drags //M- - mouseDown:(NXEvent *)spTheEvent { NXEvent *spNextEvent; int iOldMask, iCheckMask, iDragged = 0; char bvBuf[64]; [self lockFocus]; iOldMask = [window eventMask]; iCheckMask = NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK; [window setEventMask:(iOldMask|iCheckMask)]; sFirstMouseDown = spTheEvent->location; [self convertPoint:&sFirstMouseDown fromView:nil]; yLooping = 1; while (yLooping) { iDragged = 1; spNextEvent = [NXApp getNextEvent:iCheckMask]; if ((yLooping = (spNextEvent->type != NX_MOUSEUP))) { sMouseDown = spTheEvent->location; [self convertPoint:&sMouseDown fromView:nil]; [self display]; } } [self unlockFocus]; [window setEventMask:iOldMask]; if (!iDragged) return self; // For sake of aesthetics, address 0x0 is not exactly at bottom of // view. This lets the user drag an address of less than zero, // which ends up as a very high address in an unsigned long. // The next bits use the view coords to keep user from screwing up. if (sFirstMouseDown.y < VERT_MARGIN) sFirstMouseDown.y = VERT_MARGIN; if (sMouseDown.y < VERT_MARGIN) sMouseDown.y = VERT_MARGIN; // set displayed coords for user's inspection if (toScale) { hiAddrZoom = (unsigned long)((sFirstMouseDown.y - scaleYintercept)/scaleSlope); loAddrZoom = (unsigned long)((sMouseDown.y - scaleYintercept)/scaleSlope); } else { int iCC; int iSegments = [theFile mappedSegments]; int iLoSet = 0, iHiSet = 0; // find out where the addresses dragged out are for (iCC = iSegments - 1; iCC > -1 && (!iLoSet || !iHiSet); --iCC) { if (!iLoSet && addressMap[iCC].yCoordBase <= sMouseDown.y && addressMap[iCC].yCoordTop >= sMouseDown.y) { loAddrZoom = (unsigned long)((sMouseDown.y - addressMap[iCC].yCoordBase) /(addressMap[iCC].yCoordTop - addressMap[iCC].yCoordBase) *(float)(addressMap[iCC].endAddress - addressMap[iCC].baseAddress)) + addressMap[iCC].baseAddress; iLoSet = 1; } if (!iHiSet && addressMap[iCC].yCoordBase <= sFirstMouseDown.y && addressMap[iCC].yCoordTop >= sFirstMouseDown.y) { hiAddrZoom = (unsigned long)((sFirstMouseDown.y - addressMap[iCC].yCoordBase) /(addressMap[iCC].yCoordTop - addressMap[iCC].yCoordBase) *(float)(addressMap[iCC].endAddress - addressMap[iCC].baseAddress)) + addressMap[iCC].baseAddress; iHiSet = 1; } } if (!iLoSet) { // sMouseDown.y not in range of any segment if (sMouseDown.y > addressMap[0].yCoordTop) loAddrZoom = hiAddr; else loAddrZoom = loAddr; } if (!iHiSet) { // sFirstMouseDown.y not in range of any segment if (sFirstMouseDown.y > addressMap[0].yCoordTop) hiAddrZoom = hiAddr; else hiAddrZoom = loAddr; } } // user may have dragged from bottom to top. if (hiAddrZoom < loAddrZoom) { unsigned long ulTmp = hiAddrZoom; hiAddrZoom = loAddrZoom; loAddrZoom = ulTmp; } // clamp zoomed values no matter what they calculated out as if (hiAddrZoom > hiAddr) hiAddrZoom = hiAddr; if (loAddrZoom < loAddr) loAddrZoom = loAddr; sprintf(bvBuf, "0x%x", loAddrZoom); [minAddress setStringValue:bvBuf]; sprintf(bvBuf, "0x%x", hiAddrZoom); [maxAddress setStringValue:bvBuf]; [zoomButton setEnabled:YES]; return self; } //M+ - zoom:sender // PURPOSE: // Do what needs to be done when user clicks on "zoom" button. // Essentially, it pushes the current state (high address displayed, // low address displayed, and amount of mapped address taked up) // on the zoom stack, recalcs the amount of address taken up // inside the new high and low addresses, then redisplays. //M- - zoom:sender { struct zoomAddress *spZoom; int iCC; // save current "zoom state". spZoom = malloc(sizeof(struct zoomAddress)); assert(spZoom != NULL); spZoom->hiAddr = hiAddr; spZoom->loAddr = loAddr; spZoom->sumAddr = sumAddr; [zoomStack push:(void *)spZoom]; hiAddr = hiAddrZoom; loAddr = loAddrZoom; // recalculate the amount of the address used by file's mapped segments sumAddr = 0; for (iCC = [theFile mappedSegments] - 1; iCC > -1; --iCC) { id oSegment = [theFile mappedSegment:iCC]; unsigned long ulBaseAddr, ulUpperAddr; ulBaseAddr = [oSegment getBaseAddress]; ulUpperAddr = [oSegment getUpperAddress]; if (ulBaseAddr > hiAddr) break; if ( (ulUpperAddr <= hiAddr && ulBaseAddr >= loAddr) ||(ulUpperAddr >= loAddr && ulBaseAddr < loAddr) ||(ulUpperAddr > hiAddr && ulBaseAddr < hiAddr) ) { sumAddr += (ulUpperAddr <= hiAddr ? ulUpperAddr : hiAddr) - (ulBaseAddr >= loAddr ? ulBaseAddr : loAddr); } } [unzoomButton setEnabled:YES]; [self display]; return self; } //M+ - unzoom:sender // PURPOSE: // "unzoom" a level. //M- - unzoom:sender { char bvBuf[64]; struct zoomAddress *spZoom; spZoom = (struct zoomAddress *)[zoomStack pop]; loAddr = spZoom->loAddr; hiAddr = spZoom->hiAddr; sumAddr = spZoom->sumAddr; free(spZoom); sprintf(bvBuf, "0x%x", loAddr); [minAddress setStringValue:bvBuf]; sprintf(bvBuf, "0x%x", hiAddr); [maxAddress setStringValue:bvBuf]; if ([zoomStack isEmpty]) [unzoomButton setEnabled:NO]; [self display]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.