Michael is a senior compiler developer for MetaWare with over 16 years of compiler development and management experience. He can be contacted at 408-429-6382.
When it comes to writing software for multiple operating systems and microprocessors, you really only have two choices: design portability into your code from the start, or wait until you are forced into expensive rewrites.
Where I work (MetaWare), we often have to quickly port a compiler from one platform to another. It isn't unusual to have a compiler that compiles itself on the new platform (that is, a particular processor/OS combination) in six to eight weeks, with one to two people working on the project. This is possible because portability--the ability to compile, run, and achieve close to the same results as well as the same look-and-feel across platforms--was designed into the compiler from the very beginning. In this article, I'll discuss some of the techniques we've developed that you can use to enhance the portability of your code.
MetaWare got started in the compiler business in 1983 because we were having difficulty porting our parser generator to various Pascal compilers. These problems motivated us to write a portable compiler of our own. In moving to various processors and operating systems, we distilled some knowledge of the problem areas in writing transportable code.
Some people believe that if you write in C or C++ and stick to the latest ANSI or de facto standard, your code is automatically portable. If they're a bit more savvy, they may allow that you need some kind of platform-specific GUI-development package. These are the same people likely to storm into your office when you tell them that it will take six months and a rewrite of some modules to port application XYZ to a new platform.
To keep tempests out of your office, here are some things to think about when writing code:
Your code should contain safety checks to prevent you from relying too much on a particular word size or floating-point representation.
The problem with code that does a lot of floating-point calculation is that the precision of the results and the execution speed of the code may vary widely from one architecture to another. Even on a machine that has some variation of IEEE floating point, the defaults as to which kinds of overflow traps are signaled or ignored can vary. On the 80387 and Motorola 68040, the varying frequencies with which compilers store floating-point results to memory can significantly affect the accuracy of your results. Are the potential target platforms flexible--through library calls or some other mechanism--in determining how rounding will occur, when results are stored, and what traps are signaled? If not, you should consider implementing your own extended-precision floating-point operations. The MetaWare C compiler, for example, maintains its own internal version of a floating-point constant and constant operations. When necessary, the compiler converts floating-point constant results to the representation of the target architecture.
"Portable" applications should have roughly the same look-and-feel across platforms. When you port an application that is interactive and heavily dependent on floating point (a CAD package, for example) to a new architecture, some algorithms run too slowly. This is because they depended upon some capability of the original architecture (such as built-in transcendental instructions) for reasonable run-time performance. With the trend toward RISC architectures, you may want to examine your code for such hot spots and change the algorithm. You might even write your own transcendental routines to insulate the application from performance changes across platforms.
Alignment of data is a problem mainly when your application depends on transmitting binary data across platforms, or uses different language processors on the same platform. Aside from the obvious endianness difficulties, there are variations in field alignment. This often necessitates representing the binary data in textual form or having a data broker perform the necessary transformations between the two architectures. Consider the "bad" C code in Example 1(a), which was intentionally written to demonstrate alignment problems. The alignment of the various structure fields will vary from one compiler to another and from one architecture to another. Imagine trying to write this to a binary file and read it back on another platform! Even with the same language processor, this structure will vary in size, due to memory "holes"; for example, on SPARC sizeof(mystruct)=24 bytes, on 80386 sizeof(mystruct)=16 bytes, and on HP-PARISC sizeof(mystruct)=24 bytes.
The problem is worse, of course, in languages like Fortran. If you write code like that in Example 1(b), it may compile and run on some architectures, while others will cause a trap at run time. On the Intel i860 processor, doing a load of a double-precision value that is not aligned on a double-precision boundary is difficult and slow, and some compilers don't support it. Other RISC architectures have similar problems. Note that the Fortran code in Example 1(b) fits within the ANSI standard; it does not fit our definition of portability, however. You should examine your data structures, regardless of the programming language you use, and ensure that structure and union fields are aligned on common, natural boundaries.
There may soon be some light on the horizon to help with some of the binary-data compatibility problems, in the form of SOM (system object model), which allows a common binary format for objects across architectures and languages. SOM meshes with the activities of CORBA, which may eventually allow different C++ compilers to share a common object format.
The Fortran programming community that depends on de facto characteristics of old compilers may be in for a rude shock as vendors write new Fortran-90 compilers. I'm always amazed at code such as that in Example 1(c) that lives on in many applications. This code depends on zero initialized memory and static allocation of local variables. With its RECURSIVE keyword and name-space rules, Fortran-90 encourages automatic allocation of local variables. Most optimizers will not perform up to their potential if you use statically allocated variables.
C programmers are not exempt from writing absurdities, either. The most common used to be the use of the register specifier. Most optimizing compilers now ignore the register specifier altogether. If you move your code from one architecture to another, you can't expect the same set of variables to be maintained in registers across architectures. Usually, the register allocator can do a better job than a person of choosing registers and keeping the choices optimal as the source code changes.
Occasionally, an application has to manipulate data that is inherently operating-system dependent. Listing Three (page 94) shows a class definition for managing processes. This code encapsulates everything your application might need to know about a process, regardless of the underlying operating system. Note that operating-system dependent actions such as stepping the process by an instruction are deferred to member functions that can be extremely operating-system specific. The remainder of the application, however, uses these operations through the class definition in Listing Three, allowing you to isolate the OS-specific code from the rest of the application. Virtual functions (which are not used here) can also help you to isolate system dependencies by allowing you to fill in a specific member function that matches a particular OS.
If the application's user interface is more complicated than a simple command-line switch interpreter, you'll need to consider a GUI manager. Since X Windows is available on almost all UNIX systems, you could create a relatively portable system by taking into consideration X Windows, Microsoft Windows, OS/2, character-based MS-DOS, and Apple Macintosh. However, if you can find a reliable vendor who has already encapsulated these APIs for you, it's probably worth your money to buy the class libraries. Be aware, however, that some GUI vendors depend on a Motif layer, which is not supplied with the product, and not bundled with the OS by many vendors.
Another consideration in GUI class-library selection is the trend toward software internationalization. If possible, examine the source code and see how hard this is going to be for you. A good technique is to group all of the messages that a user might see in a single table or separate resource file. Then the input and output can be translated without affecting the remainder of the application. If your system allows, you may even be able to have different national-language versions of the user interface in DLLs that can be loaded on demand.
Taking all of these different factors into consideration as you write a new application or port an old one seems like a lot of extra effort. However, if you design portability in from the beginning, you'll save yourself a lot of effort later.
(a)
#include <stdio.h>
struct bad_layout{
char direction;
union {
char var;
float fvar;
double dvar;
} mess;
int myint;
};
main(){
struct bad_layout mystruct;
printf("sizeof(mystruct) = %d\n", sizeof(mystruct));
}
(b)
COMMON /SLOW/ I,D,L
EQUIVALENCE (D,N(2)),(I,N(1))
INTEGER I,N(2)
DOUBLE PRECISION D
LOGICAL L
PRINT *,D
END
(c)
SUBROUTINE USELESS(I,J)
INTEGER I,J
IF (J.EQ.0) GOTO 10
I = J ** 2
GOTO 20
10 I = 3
J = 10
20 CONTINUE
END
/* Machine dependent information required by front-end */
#ifndef CALLCONV_H
#include "callconv.h"
#endif
#ifndef LANGUAGE_H
#include "language.h"
#endif
#ifndef FP_H
#include "fp.h"
#endif
#ifndef TCLASSES_H
#include "tclasses.h"
#endif
typedef unsigned long inline_flags_type;
typedef enum {
CPU_unknown,
CPU_I386, /* Intel 386 */
CPU_370, /* IBM 370 */
CPU_RT, /* IBM RT */
CPU_AM29K, /* AM29000 */
CPU_I860, /* Intel 860 */
CPU_MC68000, /* Motorola 68000 */
CPU_MC68020, /* Motorola 68020 */
CPU_VAX, /* DEC VAX */
CPU_MDD, /* McDonald Douglas */
CPU_SPARC, /* SPARC (Sun 4) */
CPU_R3000, /* MIPS R3000 */
CPU_HOBBIT,
CPU_PARISC, /* HP9000-600/700/800 PA-RISC */
CPU_Ix86, /* 80x86 -- 16-bit Intel */
CPU_RS6000, /* IBM RS-6000 */
CPU_PPC /* IBM Power PC */
} CPU_type;
/*Object module formats*/
typedef enum {
NOFORMAT, /* OMF not applicable or unknown*/
COFF, /* Basic AT&T COFF */
AMDCOFF, /* AMD version of COFF */
LAMDCOFF, /*AMD version of COFF (little-endian mode) */
INTELOMF, /* Intel OMF (MSDOS) */
ADOTOUT, /* BSD a.out */
ELF, /* SVR4 ELF format */
MACH, /* MACH object module format */
HPUXCOFF, /* HPUX version of COFF */
} objformat_type;
/* Operating systems */
typedef enum {
NOOS, /* OS unknown */
AIX_OS, /* IBM's UNIX */
BSD_OS, /* Berkeley UNIX BSD4.x */
SUN_OS, /* Sun OS */
ATT_OS, /* AT&T UNIX System V.3 */
EPI_OS, /* EPI-OS (AM29000) */
VMS_OS, /* DEC */
MSDOS_OS, /* MS-DOS */
OS2_OS, /* OS/2 */
XNX_OS, /* Xenix */
ISIS_OS, /* Isis */
ATT4_OS, /* AT&T UNIX System V.4 */
NeXT_OS, /* NeXTStep from NeXT */
NEWS_OS, /* Sony NEWS-OS */
MSNT_OS, /* Microsoft NT */
SOL_OS, /* Solaris */
HPUX_OS, /* HP UNIX System V. */
} os_type;
/* Inline transcendentals */
#define SIN_INLINE 0x00000001
#define COS_INLINE 0x00000002
#define ASIN_INLINE 0x00000004 /* Arcsin or Arccos */
#define SQRT_INLINE 0x00000008
#define LOG_INLINE 0x00000010 /* Natural or common log */
#define EXP_INLINE 0x00000020
#define TAN_INLINE 0x00000040
#define ATAN_INLINE 0x00000080
#define ATAN2_INLINE 0x00000100 /* Arctan(a,b) */
#define SINH_INLINE 0x00000200
#define COSH_INLINE 0x00000400
#define TANH_INLINE 0x00000800 /* tanh */
#define FABS_INLINE 0x00001000 /* fabs */
#define ASM_INLINE 0x00002000 /* ASM directive supported */
#define INS_INLINE 0x00004000 /* _inline(bytes) */
/* Status of pragma processing: */
typedef enum {
OKAY_DELETE_p, /* Pragma fully processed; do not pass to backend */
OKAY_PASS_p, /* Pass pragma to back-end */
TOO_LATE_p, /* Pragma specified too late */
ERROR_p, /* Suboperands of pragma incorrect */
/* badptr set to bad parameter */
IGNORED_p, /* Already specified */
} PRAG_STATUS;
struct struct_aligns {char if_its_this_big, align_to_this;};
extern struct mapping_entry{
/* False if structs are packed by default */
bool align_members;
ubyte shortsize; /* size of "short" in bytes */
ubyte intsize; /* size of "int" in bytes */
ubyte longsize; /* size of "long" in bytes */
ubyte floatsize; /* size of "float" */
ubyte doublesize; /* size of "double" */
ubyte longdoublesize;/* size of "long double" */
ubyte min_parm_align;/* Min alignment of a passed parm */
bool unsigned_char; /*"char" unsigned by default? */
bool pure_32_bit; /* All integer operations in 32 bits?*/
ubyte code_ptr_size; /* Code pointer size */
ubyte data_ptr_size; /* Data pointer size */
/* Size of "near" pointer to code */
ubyte near_code_ptr_size;
/* Size of "far" pointer to code */
ubyte far_code_ptr_size;
/* Size of "near" pointer to data */
ubyte near_data_ptr_size;
/*Size of "far" pointer to data */
ubyte far_data_ptr_size;
ubyte short_align; /* Alignment of shorts */
ubyte long_align; /* Long alignment */
ubyte int_align; /* int alignment */
ubyte ptr_align; /* pointer alignment */
ubyte double_align; /* double alignment */
ubyte max_field_align; /* Maximum field alignment */
bool msb_first; /*integers stored MSB first? */
/* Align all vars to int boundary (even chars) */
bool word_align_vars;
bool off_boundary_refs;/* Are off-boundary refs supported?*/
char *version; /* Version number of compiler */
/* Align structs 3 bytes or longer to word boundary */
bool word_align_structs;
calling_convention_set default_calling_convention;
/* If true varargs must be explicitly specified with "..." syntax */
bool ansi_varargs_only;
/* Which transcendentals may be inline? */
inline_flags_type inline_flags;
ubyte max_parm_align;/* Max alignment of a passed parm */
ubyte offset_size; /* Pascal offset size */
ubyte area_size; /* Pascal area size */
/* Largest array in bytes (Pascal) */
unsigned long max_data_size;
bool signed_halfwords_preferred; /*True for 370. (Pascal)*/
bool range_checks_require_range; /*Do we need a lower and upper
value for rangecheck?*/
/* How are Pascal sets mapped? */
/* Also see "set_unit_size" below */
bool sets_mapped_LSB_first;
/* used in machines where pointer arithmetic will not work unless the
* computed address is a multiple of machine's word size. */
ubyte address_resolution;
/* In creating a common block for Professional Pascal interface packages,
* we use the name of the package, prefixed and suffixed with a
* special character. */
/* char to be prefixed to Pascal package block*/
char package_prefix;
/* char to be suffixed to Pascal package block*/
char package_suffix;
/* size of "char" in bytes, believe it or not char is 8 bytes on NAM */
ubyte charsize;
/* Format of floating point */
real_form floating_point_format;
/* If off-boundary references are NOT supported, do we
* handle packed structures nevertheless? */
bool packed_structs_supported;
ubyte char_align; /*Alignment of "char" */
ubyte float_align; /*Alignment of "float" */
ubyte longdouble_align; /*Alignment of "long double" */
char bits_per_int; /*bits per integer used for bitfields */
/* Implies the machine can convert (signed|unsigned)(char|short) to float
* in a way more efficient than to double. The result is that the front
* end is careful to generate FLT vs FLTU in this context so back end can
* tell from register length and FLT/FLTU whether to generate the better
* code and which kind of better code (it differs from U to nonU). */
bool short_to_float;
/* Given the case index of a pseudo-function that target machine is
* usually supports, do we support it with corrent configuration? */
bool (*recognize_pseudo_function)(func_case_index);
CPU_type cpu; /* Target CPU */
os_type os; /* Target OS */
objformat_type omf; /*Target OMF*/
/* For non-padded structs, search this array, terminated by {0,0}.
* If struct size is >= first member, align to at least 2nd member.
* Thus "word_align_structs" could be {3,4},{2,2},{0,0}. */
struct struct_aligns *struct_aligns, *array_aligns;
bool use_INFO; /* Can code generator tolerate INFO
* rather than LINE/FILE/STAB ? */
type_class wchartype; /* this can be any intger type */
ubyte wcharsize; /* sizeof (wchar_t) */
/* We changed the way debugger information is passed to code generator.
* If "debug_info_scheme" is 0, then old way is used. Otherwise, the
* new way. */
ubyte debug_info_scheme;
bool try_supported;
bool wchar_is_short; /* wchar_t is short int */
bool wchar_is_long; /* wchar_t is long int */
/* Given a toggle that may have been defined in
* establish_machine_dependencies, is it still good at this point? */
/* Return TRUE if so. Otherwise, the compiler will issued */
/* "Toggle cannot be specified here." */
bool (*toggle_is_valid)(toggle t, bool turn_it_on);
/* "init", if not zero, is called when the first non-pragma is seen.
* Its primary purpose is to adjust other fields in mapping that are
* dependant on pragmas and toggles. E.g. 1167 toggle for 386 causes long
* doubles to be 8 bytes instead of 12 */
void (*init)(void);
/* The default global aliasing convention. NULL implies "%r". */
char *global_aliasing_convention;
/* Are "far" variables support? That is, does it make
* sense to qualify a variable declaration with "_far"? */
/* This must be FALSE on ESA/370. */
bool far_variables_supported;
/* Are "far" functions supported? If false, compiler will */
/* ignore "_far" and issue a warning. */
bool far_functions_supported;
/* Does the target machine's OMF handle multiple named */
/* control sections (segments)? */
/* If this is false, then the front-end will ignore */
/* "pragma code", "pragma literals(xx)", and "pragma static_segment()". */
/* (Pragma data is handled on UNIX by converting to named blocks). */
bool multiple_named_sections_supported;
/* Can control sections of class "common" be initialized? */
/* On DOS and VMS this is true. */
bool common_section_initialization_supported;
/* Are we generated code for a strict IEEE machine? */
/* If true, we must generate unordered comparisons. */
/* I.e., X < Y is a different operation than !(X >= Y). */
bool IEEE_unordered_compares_supported;
/* code_sections_supported -- if true, the target machine */
/* had separate I & D spaces but is able to reference the */
/* I space as data. (E.g.,386 with its segment override). */
/* If set to TRUE, the toggles "const_in_code" and "literals_in_code"
* will be supported for putting const variables into instruction space.*/
bool code_sections_supported;
/* Is the calling convention "CALLEE_POPS_STACK" supported? */
bool callee_pops_stack_supported;
/* Is the calling convention "REVERSE_PARMS" supported? */
/* (Applies to those machines that have a "PUSH" instruction only. */
bool reverse_parms_supported;
/* Default data aliasing convention for Professional Pascal */
/* Default routine aliasing convention for Professional Pascal */
char *data_aliasing_convention;
char *routine_aliasing_convention;
/* set_unit_size in conjunction with the "sets_mapped_LSB_first" */
/* flag above determine how (Pascal) sets are mapped in storage. */
/* High C/Professional Pascal ordinarily maps sets as a sequence
* of halfwords. Microsoft maps them as an even number of bytes,
* MSB first. */
ubyte set_unit_size;
/* type_checking is true if type information should be kept even when
* g_flag is off. This is used for 370/ESA type checking at link time. */
bool type_checking;
/* Size of a "long long" type. If such types are not supported,
* then the size should match "long". */
ubyte longlongsize;
ubyte longlong_align; /* Alignment of long long */
/* What is the largest auto-variable of type struct that can be mapped
* directly into a series of one or more registers? Value is in bytes. */
uint largest_aggregate_in_registers;
/* When doubles or long doubles are just plain variables (or arrays
* thereof), what should the alignment be? For Pentium, it's much
* better for them to be 8-byte aligned. */
ubyte double_variable_align; /*double variable alignment */
/*Alignment of "long double" variable */
ubyte longdouble_variable_align;
bool supports_call_lit; /* Code generator supports call-lit construct.*/
/* These tell if we require certain calling convention bits: */
/* Must have cc_CALLEE_POPS_STACK.*/
bool callee_pops_stack_required;
bool reverse_parms_required;/* Must have cc_REVERSE_PARMS.*/
/* For C++ constructors/destructors of static/global variables, does
* get handle the initialization level protocol? True for systems
* that support .init/.fini sections. */
bool support_initialization_order;
/* Use Sun's and AT&T's convention for mapping bit fields? */
bool ABI_bit_fields;
/* SYS_SIZETTYPE takes on one of the values s, i, l for short, int, long.
* SYS_SIZETSIGNED takes one of the values s, u, or n for signed,
* unsigned or non-signed (for "char"). */
char sizet_signed; /* s, u, n. */
char sizet_type; /* s, i, l. c not supported currently. */
}mapping;
extern const char *machine_name; /*Name of machine*/
#define LONGLONG_SUPPORTED (SYS_LONGLONGSIZE > SYS_LONGSIZE)
#define SYS_PACKEDSTRUCT (!mapping.align_members)
/* CHARSIZE is always the same on all machines. Wrong!! not on NAM */
#define SYS_CHARSIZE mapping.charsize
#define SYS_INTSIZE mapping.intsize
#define SYS_FLOATSIZE mapping.floatsize
#define SYS_DOUBLESIZE mapping.doublesize
#define SYS_EXTENDEDSIZE mapping.longdoublesize
#define SYS_LINKSIZE mapping.near_data_ptr_size
#define SYS_LONGLONGSIZE mapping.longlongsize
#define SYS_SHORTSIZE mapping.shortsize
#define SYS_LONGSIZE mapping.longsize
#define SYS_SIGNEDCHAR (!mapping.unsigned_char)
/*Pointer that is loaded into reg*/
#define SYS_PTRSIZE SYS_LINKSIZE
#define SYS_DPTRSIZE mapping.data_ptr_size
#define SYS_CPTRSIZE mapping.code_ptr_size
#define SYS_WCHARSIZE mapping.wcharsize
#define SYS_WCHARTYPE mapping.wchartype
#define SYS_WCHARSHORT mapping.wchar_is_short
#define SYS_WCHARLONG mapping.wchar_is_long
#define SYS_SIZETSIGNED mapping.sizet_signed
#define SYS_SIZETTYPE mapping.sizet_type
#define BITS_PER_BYTE 8
#define BITS_PER_INT mapping.bits_per_int
#define BITS_PER_LONG (sizeof(long)*BITS_PER_BYTE)
#define SYS_INTAL mapping.int_align
#define SYS_LONGAL mapping.long_align
#define SYS_LONGLONGAL mapping.longlong_align
#define SYS_SHORTAL mapping.short_align
#define SYS_FLOATAL mapping.float_align
#define SYS_CHARAL mapping.char_align
#define SYS_DOUBLEAL mapping.double_align
#define SYS_LONGDOUBLEAL mapping.longdouble_align
#define SYS_DOUBLE_VARIABLE_AL mapping.double_variable_align
#define SYS_LONGDOUBLE_VARIABLE_AL \
mapping.longdouble_variable_align
#define SYS_PTRAL mapping.ptr_align
#define SYS_OFF_BOUNDARY_REFS mapping.off_boundary_refs
#define SYS_STRINGAL 1 /*Alignment of strings*/
#define SYS_MSB_FIRST mapping.msb_first
#define SYS_LSB_FIRST (!SYS_MSB_FIRST)
#define SYS_STACK_AL mapping.min_parm_align
#define SYS_32_BIT_ARITHMETIC_ONLY mapping.pure_32_bit
#define SYS_MAX_FIELD_AL mapping.max_field_align
#define SYS_WORD_ALIGN_STRUCTS mapping.word_align_structs
#define SYS_ADR_RESOLUTION mapping.address_resolution
#define SEGMENT_REG_SIZE (mapping.far_data_ptr_size - \
SYS_INTSIZE )
#define NEW_DEBUG_INFO (mapping.debug_info_scheme> 0)
/* Establish_machine_dependencies -- initializes "mapping" to correspond
* to "machine". Returns FALSE if machine is not recognized. */
extern bool establish_machine_dependencies(
const char *machine, language_type l);
/* Defines which object module formatter should be used for the target OS and
* machine name of the target operating system passed by the driver */
extern const char *targetos_name;
#define LS (sizeof(long)*8) /* Maximum bits for left shift */
#define BS (sizeof(long long)*8) /* Maximum bits for long long shift */
struct longlong{ /* Define structure for systems that don't support long long*/
long lo;
long hi;
};
typedef struct longlong Big_int;
/* Grab a mantissa from a floating point number */
static long extract_mantissa(FP_number F){
Big_int b;
int cnt, rbit;
cnt = BS -1 - F->Exp; /* Determine how far to shift to find exponent */
if (cnt >= LS){ /* If shifting at least a longword */
cnt -= LS; /* subtract longword length from shift count */
if (cnt == 0)
rbit = long(b.lo) < 0; /* Guard bit needed? */
b.lo = b.hi;
b.hi = 0;
}
if (cnt){ /* Anything left to shift? */
rbit = (b.lo & (1L << (cnt-1))) !=0;
if (cnt == LS){ /* Some machines can't shift by long word length */
b.lo = 0; /* Defend against this. Result would be zero */
b.hi = 0;
}
else{
b.lo = ((unsigned long)b.lo >> cnt | (b.hi << (LS-cnt));
b.hi = (unsigned long) b.hi >> cnt;
}
}
}
#ifndef Process_h
#define Process_h
#include "addrvect.h"
#include "disassem.h"
#include "itemnumb.h"
#include "linklist.h"
#include "memacces.h"
#include "modulemg.h"
#include "stmt.h"
#include "symbolta.h"
#include "tempbkpt.h"
typedef int Outcome;
#define user_failure -1
#define failure 0
#define success 1
class Declaration;
class DiFile;
class EventMgr;
class ExecSpec;
class ExprObj;
class StackFrame;
class Status;
class Thread;
enum PSA1 { psa1_none,
psa1_replace_breakop,
psa1_replace_libpt,
};
enum PSA2 { psa_none,
psa_run_to_retaddr,
};
class Process : public ItemNumber {
Key key;
Thread * current; // 0 in ctor
LinkList threadlist;
TempBkptMgr tempbkptmgr;
EventMgr * eventmgr; // set in ctor
MemAccess memaccess;
Disassembler disassembler;
Symboltable symboltable;
ModuleMgr modulemgr;
AddrVector destvector;
Stmt startstmt;
Boolean now_executing;
DiFile * target_difile;
PSA1 psa1;
PSA2 psa2;
char *current_lang; // Temporary hack to be able
// to set the language.
Thread * lookup_thread( unsigned int );
Outcome check_state();
Outcome set_execspec( const ExecSpec & );
Boolean goal_attained();
Outcome start_step_into( Thread * );
Outcome start_step_over( Thread * );
Outcome start_step_retaddr( Thread * );
Outcome start_run( Thread * );
Outcome analyse_stmt_into( Boolean & );
Outcome analyse_stmt_over( Boolean & );
Outcome run_to_return_addr( Thread * );
Outcome execute_to_return_addr( Thread * );
Outcome run_to_caller( Thread * );
Outcome end_instr_step_into( Thread * );
Outcome end_instr_step_over( Thread * );
Outcome end_stmt_step_into( Thread * );
Outcome end_stmt_step_over( Thread * );
Outcome end_run( Thread * );
Outcome check_instr_step_into( Thread * );
Outcome check_instr_step_over( Thread * );
Outcome check_stmt_step_into( Thread * );
Outcome check_stmt_step_over( Thread * );
Outcome check_run( Thread * );
Outcome respond_to_hop_completion( Thread * );
Outcome respond_to_retpoint( Thread * );
Outcome respond_to_destpoint( Thread * );
Outcome respond_to_breakpoint( Thread * );
Outcome respond_to_watchpoint( Thread * );
Outcome respond_to_exception( Thread * );
Outcome respond_to_step_completion( Thread * );
Outcome respond_to_suspension( Thread * );
Outcome respond_to_exec( Thread *, DiFile * );
Outcome respond_to_libpt( Thread * );
Outcome respond_to_module_load( const Status & );
Outcome respond_to_module_unload( const Status & );
Outcome respond_to_thread_creation( const Status & );
Outcome respond_to_thread_destruction( const Status & );
Outcome start_stmt_step_into( Thread * );
Outcome start_stmt_step_over( Thread * );
public:
Process( unsigned int, DiFile * );
~Process();
Outcome get_status( Status & );
Outcome wait_status( Status & );
Outcome update_status( const Status & );
Boolean is_executing() { return now_executing; }
Outcome run( const ExecSpec & );
Outcome instr_step_into( const ExecSpec & );
Outcome instr_step_over( const ExecSpec & );
Outcome stmt_step_into( const ExecSpec & );
Outcome stmt_step_over( const ExecSpec & );
Outcome resume();
Outcome stop();
Thread * current_thread() { return current; }
Outcome disassemble( const Addr &, Instruction &, Addr & );
Outcome find_stmt( const Addr &, Stmt & );
Outcome find_function( const Addr &, Declaration & );
Outcome evaluate( char *, StackFrame &, ExprObj & );
Outcome set_language(char *input_language);
char *get_lang_string();
Process * next() { return (Process *)Item::get_next(); }
};
#endif
Copyright © 1994, Dr. Dobb's Journal