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.