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.