diff --git a/Tools/WAD/Include/wad.h b/Tools/WAD/Include/wad.h index 68b2c88ca..dfad57360 100644 --- a/Tools/WAD/Include/wad.h +++ b/Tools/WAD/Include/wad.h @@ -33,6 +33,8 @@ extern "C" { #define MAX_PATH 1024 #endif +#define WAD_SRC_WINDOW 2 + /* --- Low level memory management functions --- */ extern int wad_memory_init(); @@ -140,24 +142,28 @@ typedef struct WadFrame { /* Symbol table information for PC */ - char *sym_name; /* Symbol name */ - char *sym_file; /* Source file (if any) */ - unsigned long sym_base; /* Symbol base address */ - unsigned long sym_size; /* Symbol size */ - int sym_type; /* Symbol type */ - int sym_bind; /* Symbol binding */ + char *sym_name; /* Symbol name */ + char *sym_file; /* Source file (if any) */ + unsigned long sym_base; /* Symbol base address */ + unsigned long sym_size; /* Symbol size */ + int sym_type; /* Symbol type */ + int sym_bind; /* Symbol binding */ /* Location information */ - char *loc_objfile; /* Object filename */ - char *loc_srcfile; /* Source filename */ - int loc_line; /* Source line */ + char *loc_objfile; /* Object filename */ + char *loc_srcfile; /* Source filename */ + int loc_line; /* Source line */ /* Debugging information */ - int debug_nargs; /* Number of arguments */ - WadLocal *debug_args; /* Arguments */ - WadLocal *debug_lastarg; /* Last argument */ + int debug_nargs; /* Number of arguments */ + WadLocal *debug_args; /* Arguments */ + WadLocal *debug_lastarg; /* Last argument */ - int last; /* Last frame flag */ + /* Output strings */ + char *debug_str; /* Debugging string */ + char *debug_srcstr; /* Source string */ + + int last; /* Last frame flag */ } WadFrame; extern WadFrame *wad_stack_trace(unsigned long, unsigned long, unsigned long); @@ -190,6 +196,8 @@ extern void wad_find_debug(WadFrame *f); extern void wad_build_vars(WadFrame *f); extern char *wad_format_var(WadLocal *l); +extern void wad_debug_make_strings(WadFrame *f); + /* --- Debugging Interface --- */ #define DEBUG_SEGMENT 0x1 diff --git a/Tools/WAD/Makefile b/Tools/WAD/Makefile index 8f9a31d98..b32dba8c1 100644 --- a/Tools/WAD/Makefile +++ b/Tools/WAD/Makefile @@ -21,7 +21,7 @@ wad: @cd Wad; $(MAKE) wad python: - @cd Wad; $(MAKE) SINCLUDE='$(PYINCLUDE)' python + @cd Python; $(MAKE) SINCLUDE='$(PYINCLUDE)' python tcl: @cd Wad; $(MAKE) SINCLUDE='$(TCLINCLUDE)' tcl diff --git a/Tools/WAD/Makefile.in b/Tools/WAD/Makefile.in index 6fc8686a6..29067ecb3 100644 --- a/Tools/WAD/Makefile.in +++ b/Tools/WAD/Makefile.in @@ -20,7 +20,7 @@ wad: @cd Wad; $(MAKE) wad python: - @cd Wad; $(MAKE) SINCLUDE='$(PYINCLUDE)' python + @cd Python; $(MAKE) SINCLUDE='$(PYINCLUDE)' python tcl: @cd Wad; $(MAKE) SINCLUDE='$(TCLINCLUDE)' tcl diff --git a/Tools/WAD/Python/Makefile.in b/Tools/WAD/Python/Makefile.in index 95a704df0..0119103c9 100644 --- a/Tools/WAD/Python/Makefile.in +++ b/Tools/WAD/Python/Makefile.in @@ -6,8 +6,8 @@ ####################################################################### # These are the files that make up the WAD core -SRCS = python.c -OBJS = python.o +SRCS = type.c python.c +OBJS = type.o python.o INCLUDE = -I../Include -I. $(SINCLUDE) WADOPT = @WADOPT@ diff --git a/Tools/WAD/Python/python.c b/Tools/WAD/Python/python.c index 9457aa73f..ed09e98fe 100644 --- a/Tools/WAD/Python/python.c +++ b/Tools/WAD/Python/python.c @@ -20,6 +20,8 @@ static PyObject *buserror_exc = 0; static PyObject *abort_exc = 0; static PyObject *illegal_exc = 0; +extern PyObject *new_wadobject(WadFrame *f,int); + /* Function return points and values */ static WadReturnFunc retpts[] = { @@ -101,7 +103,7 @@ static void handler(int signo, WadFrame *frame, char *ret) { char *name; WadFrame *f; WadFrame *fline = 0; - + char *srcstr = 0; printf("python handler.\n"); if (!ret) { @@ -131,6 +133,7 @@ static void handler(int signo, WadFrame *frame, char *ret) { break; } +#ifdef OLD f = frame; /* Find the last exception frame */ while (!f->last) { @@ -139,73 +142,17 @@ static void handler(int signo, WadFrame *frame, char *ret) { /* Now work backwards */ f = f->prev; while (f) { - sprintf(temp,"#%-3d 0x%08x in ", f->frameno, f->pc); - strcat(message,temp); - strcat(message, f->sym_name ? f->sym_name : "?"); - strcat(message,"("); - strcat(message,wad_arg_string(f)); - strcat(message,")"); - if (f->loc_srcfile && strlen(f->loc_srcfile)) { - strcat(message," in '"); - strcat(message, wad_strip_dir(f->loc_srcfile)); - strcat(message,"'"); - if (f->loc_line > 0) { - sprintf(temp,", line %d", f->loc_line); - strcat(message,temp); - { - int fd; - fd = open(f->loc_srcfile, O_RDONLY); - if (fd > 0) { - fline = f; - } - close(fd); - } - } - } else { - if (f->loc_objfile && strlen(f->loc_objfile)) { - strcat(message," from '"); - strcat(message, wad_strip_dir(f->loc_objfile)); - strcat(message,"'"); - } - } - strcat(message,"\n"); + strcat(message, f->debug_str); + if (f->debug_srcstr) srcstr = f->debug_srcstr; f = f->prev; } - if (fline) { - int first; - int last; - char *line, *c; - int i; - first = fline->loc_line - 2; - last = fline->loc_line + 2; - if (first < 1) first = 1; - - line = wad_load_source(fline->loc_srcfile,first); - if (line) { - strcat(message,"\n"); - strcat(message, fline->loc_srcfile); - sprintf(temp,", line %d\n\n", fline->loc_line); - strcat(message, temp); - for (i = first; i <= last; i++) { - if (i == fline->loc_line) strcat(message," => "); - else strcat(message," "); - c = strchr(line,'\n'); - if (c) { - *c = 0; - strcat(message,line); - strcat(message,"\n"); - *c = '\n'; - } else { - strcat(message,line); - strcat(message,"\n"); - break; - } - line = c+1; - } - wad_release_source(); - strcat(message,"\n"); - } + if (srcstr) { + strcat(message,"\n"); + strcat(message, srcstr); + strcat(message,"\n"); } +#endif + if (wad_heap_overflow) { write(2, "WAD: Heap overflow detected.\n", 30); wad_default_callback(signo, frame, ret); @@ -216,7 +163,11 @@ static void handler(int signo, WadFrame *frame, char *ret) { above should dump a stack trace to stderr just in case we don't make it back. */ +#ifdef OLD PyErr_SetString(type, message); +#endif + PyErr_SetObject(type, new_wadobject(frame,0)); + } void pywadinit() { diff --git a/Tools/WAD/Python/type.c b/Tools/WAD/Python/type.c new file mode 100644 index 000000000..898ff2a99 --- /dev/null +++ b/Tools/WAD/Python/type.c @@ -0,0 +1,221 @@ +/* ----------------------------------------------------------------------------- + * type.c + * + * This file defines a new python type that contains information from + * the WAD stack trace. + * + * Author(s) : David Beazley (beazley@cs.uchicago.edu) + * + * Copyright (C) 2000. The University of Chicago + * See the file LICENSE for information on usage and redistribution. + * ----------------------------------------------------------------------------- */ + +#include "wad.h" +#include "Python.h" + +typedef struct { + PyObject_HEAD + WadFrame *frame; /* Wad Stack frame object */ + int count; /* Number of frames */ +} wadobject; + +staticforward PyTypeObject WadObjectType; + + +PyObject * +new_wadobject(WadFrame *f, int count) { + wadobject *self; + self = PyObject_NEW(wadobject, &WadObjectType); + if (self == NULL) return NULL; + + self->frame = f; + if (count > 0) { + self->count = count; + } else { + self->count = 0; + while (f) { + self->count++; + f = f->next; + } + } + return (PyObject *) self; +} + +/* release a wad object */ +static void +wadobject_dealloc(wadobject *self) { + PyMem_DEL(self); +} + +static PyObject * +wadobject_repr(wadobject *self) { + char message[65536]; + char *srcstr = 0; + WadFrame *fp = 0; + int n; + WadFrame *f = self->frame; + + strcpy(message,"[ C stack trace ]\n\n"); + /* Find the last exception frame */ + n = self->count; + while (f && n) { + fp = f; + f= f->next; + n--; + } + + if (fp) { + /* Now work backwards */ + f = fp; + while (f) { + strcat(message, f->debug_str); + if (f->debug_srcstr) srcstr = f->debug_srcstr; + if (f == self->frame) break; + f = f->prev; + } + if (srcstr) { + strcat(message,"\n"); + strcat(message, srcstr); + strcat(message,"\n"); + } + } + return PyString_FromString(message); +} + +static PyObject * +wadobject_str(wadobject *self) { + char message[65536]; + char *srcstr = 0; + int n; + + WadFrame *f = self->frame; + n = self->count; + strcpy(message,"[ C stack trace ]\n\n"); + /* Find the last exception frame */ + while (!f->last && n) { + f= f->next; + n--; + } + /* Now work backwards */ + if (n <= 0) { + f = f->prev; + } + while (f) { + strcat(message, f->debug_str); + if (f->debug_srcstr) srcstr = f->debug_srcstr; + if (self->frame == f) break; + f = f->prev; + } + if (srcstr) { + strcat(message,"\n"); + strcat(message, srcstr); + strcat(message,"\n"); + } + return PyString_FromString(message); +} + +static int +wadobject_len(wadobject *self) { + int n = 0; + WadFrame *f = self->frame; + while (f) { + n++; + f = f->next; + } + return n; +} + +static PyObject * +wadobject_getitem(wadobject *self, int n) { + int i; + WadFrame *f; + if (n < 0) { + n = self->count + n; + } + if ((n < 0) || (n >= self->count)) { + PyErr_SetString(PyExc_IndexError,"Stack frame out of range"); + return NULL; + } + f = self->frame; + for (i = 0; i next; + } + return new_wadobject(f,1); +} + +static PyObject * +wadobject_getslice(wadobject *self, int start, int end) { + int i; + WadFrame *f; + + f = self->frame; + for (i = 0; i < start; i++) { + f = f->next; + } + return new_wadobject(f,(end-start)); +} + +static PyObject * +wadobject_getattr(wadobject *self, char *name) { + if (strcmp(name,"name") == 0) { + return Py_BuildValue("z", self->frame->sym_name); + } else if (strcmp(name,"exe") == 0) { + return Py_BuildValue("z", self->frame->object->path); + } else if (strcmp(name,"source") == 0) { + return Py_BuildValue("z", self->frame->loc_srcfile); + } else if (strcmp(name,"object") == 0) { + return Py_BuildValue("z", self->frame->loc_objfile); + } else if (strcmp(name,"line") == 0) { + return Py_BuildValue("i", self->frame->loc_line); + } else if (strcmp(name,"pc") == 0) { + return PyLong_FromUnsignedLong(self->frame->pc); + } else if (strcmp(name,"sp") == 0) { + return PyLong_FromUnsignedLong(self->frame->sp); + } else if (strcmp(name,"fp") == 0) { + return PyLong_FromUnsignedLong(self->frame->fp); + } else if (strcmp(name,"stack_size") == 0) { + return PyInt_FromLong(self->frame->stack_size); + } else if (strcmp(name,"stack") == 0) { + return PyString_FromStringAndSize(self->frame->stack, self->frame->stack_size); + } else if (strcmp(name,"nargs") == 0) { + return PyInt_FromLong(self->frame->debug_nargs); + } else if (strcmp(name,"seg_base") == 0) { + return PyLong_FromUnsignedLong((long )self->frame->segment->base); + } else if (strcmp(name,"seg_size") == 0) { + return PyLong_FromUnsignedLong((long) self->frame->segment->size); + } + + PyErr_SetString(PyExc_NameError,"Unknown attribute."); + return NULL; +} +static PySequenceMethods wadobject_as_sequence = { + (inquiry) wadobject_len, + 0, + 0, + (intargfunc) wadobject_getitem, /* get item */ + (intintargfunc) wadobject_getslice, /* get slice */ + 0, + 0 +}; + +static PyTypeObject WadObjectType = { + PyObject_HEAD_INIT(&PyType_Type) + 0, + "WadObject", + sizeof(wadobject), + 0, + (destructor) wadobject_dealloc, + 0, /* printfunc */ + (getattrfunc) wadobject_getattr, + (setattrfunc) 0, + (cmpfunc) 0, + (reprfunc) wadobject_repr, + + 0, /* number */ + &wadobject_as_sequence, /* sequence */ + 0, /* mapping */ + 0, /* hash */ + 0, /* call */ + (reprfunc) wadobject_str, /* str */ +}; + diff --git a/Tools/WAD/Test/foo.py b/Tools/WAD/Test/foo.py new file mode 100644 index 000000000..6ccfd5377 --- /dev/null +++ b/Tools/WAD/Test/foo.py @@ -0,0 +1,19 @@ +import debug + +def foo(): + debug.abort_crash(-1) + +def bar(): + foo() + +def spam(): + bar() + +from Tkinter import * + +root = Tk() + +button = Button(text="Press me", command=spam) +button.pack() + +#root.mainloop() diff --git a/Tools/WAD/Test/wadpm.py b/Tools/WAD/Test/wadpm.py new file mode 100644 index 000000000..8a633129e --- /dev/null +++ b/Tools/WAD/Test/wadpm.py @@ -0,0 +1,49 @@ +# ----------------------------------------------------------------------------- +# Wad port-mortem debugger +# +# David Beazley +# ----------------------------------------------------------------------------- + +import sys + +_last_exc = None +_last_level = 0 + +print "WAD port-mortem" + +class where_impl: + def __repr__(self): + global _last_exc, _last_level + if sys.last_value: + if sys.last_value[0] != _last_exc: + _last_exc = sys.last_value[0] + _last_level = 0 + else: + raise RuntimeError,"No pending error." + print repr(_last_exc) + return "" + +where = where_impl() + +class up_impl: + def __repr__(self): + global _last_exc, _last_level + if not _last_exc: + return "" + _last_level += 1 + print repr(_last_exc[_last_level]) + return "" + +up = up_impl() + +class down_impl: + def __repr__(self): + global _last_exc, _last_level + if not _last_exc: + return "" + _last_level -= 1 + print repr(_last_exc[_last_level]) + return "" + +down = down_impl() + diff --git a/Tools/WAD/Wad/Makefile b/Tools/WAD/Wad/Makefile index f893b1974..9dbd94406 100644 --- a/Tools/WAD/Wad/Makefile +++ b/Tools/WAD/Wad/Makefile @@ -10,7 +10,7 @@ WADSRCS = vars.c io.c memory.c return.c default.c stack.c stab.c elf.c object.c init.c segment.c signal.c WADOBJS = vars.o io.o memory.o return.o default.o stack.o stab.o elf.o object.o signal.o segment.o init.o INCLUDE = -I../Include -I. $(SINCLUDE) -WADOPT = -DWAD_LINUX +WADOPT = -DWAD_SOLARIS # Location of your Python installation PYINCLUDE = -I/usr/local/include/python2.0 @@ -23,24 +23,24 @@ TCLSRCS = wadtcl.cxx TCLOBJS = wadtcl.o # Location of your Perl installation -PERLINCLUDE = -I/usr/lib/perl5/5.00503/i386-linux/CORE +PERLINCLUDE = -I/usr/perl5/5.00503/sun4-solaris/CORE PERLSRCS = wadpl.cxx PERLOBJS = wadpl.o # C Compiler -CC = gcc -CFLAGS = #-fpic +CC = cc +CFLAGS = # # C++ Compiler -CXX = c++ -CXXFLAGS = #-fpic +CXX = CC +CXXFLAGS = #-Kpic # Linking options CLINK = -CXXLINK = g++ -shared +CXXLINK = CC -G # AR -CC = ar +AR = ar # Rules for creation of a .o file from .cxx .SUFFIXES: .cxx diff --git a/Tools/WAD/Wad/default.c b/Tools/WAD/Wad/default.c index e128da668..8d3a2622b 100644 --- a/Tools/WAD/Wad/default.c +++ b/Tools/WAD/Wad/default.c @@ -83,8 +83,11 @@ char *wad_strip_dir(char *name) { return name; } + + static char *src_file = 0; static int src_len = 0; +static char src_path[1024] = ""; /* Opens up a source file and tries to locate a specific line number */ @@ -94,16 +97,22 @@ char *wad_load_source(char *path, int line) { char *start; int n; - fd = open(path, O_RDONLY); - if (fd < 0) return 0; - src_len = lseek(fd, 0, SEEK_END); - lseek(fd,0,SEEK_SET); - src_file = (char *)mmap(NULL,src_len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - if (src_file == MAP_FAILED) { + if (strcmp(src_path,path)) { + if (src_file) { + munmap(src_file, src_len); + } + fd = open(path, O_RDONLY); + if (fd < 0) return 0; + src_len = lseek(fd, 0, SEEK_END); + lseek(fd,0,SEEK_SET); + src_file = (char *)mmap(NULL,src_len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if (src_file == MAP_FAILED) { + close(fd); + return 0; + } close(fd); - return 0; - } - close(fd); + strcpy(src_path,path); + } n = 0; start = src_file; c = src_file; @@ -118,14 +127,102 @@ char *wad_load_source(char *path, int line) { c++; n++; } - munmap(src_file,src_len); - src_file = 0; return 0; } void wad_release_source() { - if (src_file) + if (src_file) { munmap(src_file,src_len); + src_file = 0; + src_len = 0; + src_path[0] = 0; + } +} + +/* ----------------------------------------------------------------------------- + * wad_debug_src_code(WadFrame *f) + * + * Get source code for a frame + * ----------------------------------------------------------------------------- */ + +char *wad_debug_src_string(WadFrame *f, int window) { + static char temp[16384]; + char ntemp[64]; + + if (f->loc_srcfile && strlen(f->loc_srcfile) && (f->loc_line > 0)) { + char *line, *c; + int i; + int first, last; + first = f->loc_line - window; + last = f->loc_line + window; + if (first < 1) first = 1; + line = wad_load_source(f->loc_srcfile,first); + if (line) { + strcpy(temp,f->loc_srcfile); + strcat(temp,", line "); + sprintf(ntemp,"%d\n\n", f->loc_line); + strcat(temp,ntemp); + for (i = first; i <= last; i++) { + if (i == f->loc_line) strcat(temp," => "); + else strcat(temp," "); + c = strchr(line,'\n'); + if (c) { + *c = 0; + strcat(temp,line); + strcat(temp,"\n"); + *c = '\n'; + } else { + strcat(temp,line); + strcat(temp,"\n"); + break; + } + line = c+1; + } + f->debug_srcstr = wad_strdup(temp); + return f->debug_srcstr; + } + } + f->debug_srcstr = 0; + return 0; +} + +/* ----------------------------------------------------------------------------- + * wad_debug_make_strings(WadFrame *f) + * + * This function walks the stack trace and tries to generate a debugging string + * ----------------------------------------------------------------------------- */ + +void +wad_debug_make_strings(WadFrame *f) { + static char msg[16384]; + char temp[1024]; + while (f) { + sprintf(msg,"#%-3d 0x%08x in ", f->frameno, f->pc); + strcat(msg, f->sym_name ? f->sym_name : "?"); + strcat(msg,"("); + strcat(msg,wad_arg_string(f)); + strcat(msg,")"); + if (f->loc_srcfile && strlen(f->loc_srcfile)) { + strcat(msg," in '"); + strcat(msg, wad_strip_dir(f->loc_srcfile)); + strcat(msg,"'"); + if (f->loc_line > 0) { + sprintf(temp,", line %d", f->loc_line); + strcat(msg,temp); + /* Try to locate the source file */ + wad_debug_src_string(f, WAD_SRC_WINDOW); + } + } else { + if (f->loc_objfile && strlen(f->loc_objfile)) { + strcat(msg," from '"); + strcat(msg, wad_strip_dir(f->loc_objfile)); + strcat(msg,"'"); + } + } + strcat(msg,"\n"); + f->debug_str = wad_strdup(msg); + f = f->next; + } } /* ----------------------------------------------------------------------------- @@ -135,6 +232,7 @@ void wad_release_source() { void wad_default_callback(int signo, WadFrame *f, char *ret) { char *fd; WadFrame *fline = 0; + char *srcstr = 0; switch(signo) { case SIGSEGV: @@ -161,60 +259,18 @@ void wad_default_callback(int signo, WadFrame *f, char *ret) { while (f && !(f->last)) { f = f->next; } + while (f) { - fprintf(stderr,"#%-3d 0x%08x in %s(%s)", f->frameno, f->pc, f->sym_name ? f->sym_name : "?", - wad_arg_string(f)); - if (f->loc_srcfile && strlen(f->loc_srcfile)) { - fprintf(stderr," in '%s'", wad_strip_dir(f->loc_srcfile)); - if (f->loc_line > 0) { - fprintf(stderr,", line %d", f->loc_line); - { - int fd; - fd = open(f->loc_srcfile, O_RDONLY); - if (fd > 0) { - fline = f; - } - close(fd); - } - } - } else { - if (f->loc_objfile && strlen(f->loc_objfile)) { - fprintf(stderr," from '%s'", f->loc_objfile); - } + fputs(f->debug_str, stderr); + if (f->debug_srcstr) { + srcstr = f->debug_srcstr; } - fprintf(stderr,"\n"); f = f->prev; } - - if (fline) { - int first; - int last; - char *line, *c; - int i; - first = fline->loc_line - 2; - last = fline->loc_line + 2; - if (first < 1) first = 1; - - line = wad_load_source(fline->loc_srcfile,first); - if (line) { - fprintf(stderr,"\n%s, line %d\n\n", fline->loc_srcfile,fline->loc_line); - for (i = first; i <= last; i++) { - if (i == fline->loc_line) fprintf(stderr," => "); - else fprintf(stderr," "); - c = strchr(line,'\n'); - if (c) { - *c = 0; - fprintf(stderr,"%s\n",line); - *c = '\n'; - } else { - fprintf(stderr,"%s\n",line); - break; - } - line = c+1; - } - wad_release_source(); - fprintf(stderr,"\n"); - } + if (srcstr) { + fputs("\n", stderr); + fputs(srcstr,stderr); + fputs("\n", stderr); } } diff --git a/Tools/WAD/Wad/signal.c b/Tools/WAD/Wad/signal.c index 99d917b4a..9583273d7 100644 --- a/Tools/WAD/Wad/signal.c +++ b/Tools/WAD/Wad/signal.c @@ -351,8 +351,12 @@ void wad_signalhandler(int sig, siginfo_t *si, void *vcontext) { if (sig == SIGSEGV) { if (addr >= current_brk) wad_heap_overflow = 1; } + wad_stack_debug(frame); + /* Generate debugging strings */ + wad_debug_make_strings(frame); + /* Walk the exception frames and try to find a return point */ origframe = frame; while (frame) { diff --git a/Tools/WAD/Wad/stack.c b/Tools/WAD/Wad/stack.c index 929f653bb..53b5c7192 100644 --- a/Tools/WAD/Wad/stack.c +++ b/Tools/WAD/Wad/stack.c @@ -44,6 +44,8 @@ new_frame() { f->debug_nargs = -1; f->debug_args = 0; f->debug_lastarg = 0; + f->debug_str = 0; + f->debug_srcstr = 0; f->last = 0; f->next = 0; diff --git a/Tools/WAD/Wad/vars.c b/Tools/WAD/Wad/vars.c index 0b4c74913..66a72b81a 100644 --- a/Tools/WAD/Wad/vars.c +++ b/Tools/WAD/Wad/vars.c @@ -91,7 +91,8 @@ char *wad_format_var(WadLocal *l) { #endif strcat(buffer,"0x"); c = buffer+2; - for (i = 0; i < l->size; i++) { + /* for (i = 0; i < l->size; i++) { */ + for (i = 0; i < 4; i++) { b = (int) *ptr; if (!leading || (b)) { if (!leading || (b & 0xf0))