module: environment-protocols synopsis: Protocols describing memory/register locations, and for obtaining data from them in various forms. author: Paul Howard Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND ///// // Describes a number base suitable for the display of data that may be // addresses. define constant = one-of(#"octal", #"decimal", #"hexadecimal"); ///// // Describes a number base suitable for the display of data that are not // addresses. define constant = one-of(#"byte-character", #"unicode-character", #"single-float", #"double-float"); ///// // A union of the above types, therefore describing a number base for // the display of arbitrary data. define constant = type-union(, ); ///// // Describes a size constraint on the importing and printing of data // read from an address. define constant = one-of(#"byte", /* 8-bit value */ #"short", /* 16-bit value */ #"long", /* 32-bit value */ #"hyper", /* 64-bit value. Terminology comes from IDL. */ #"float", /* Single-precision floating-point value */ #"double", /* Double-precision floating-point value */ #"word"); /* Platform-word-size value */ ///// // Nothing interesting is held in the class itself, except for the // inherited application proxy and project slots. define class () end class; ///// $INVALID-ADDRESS-OBJECT // This unique instance of serves as a legal member of // the type, but without any valid interpretation. This is used in // preference to #f as a failing result or argument. define constant $invalid-address-object = make(, application-object-proxy: #f); ///// ADDRESS-TO-STRING // Synopsis: Converts an abstract address into a printable string. // Inputs: // server - The backend dispatching object. // address - Instance of to be printed. // format - The format (number base) of the required string. // (Note: The size of the data is dictated by the runtime // platform, so is not supplied to this function). // Outputs: // A string of fixed size per runtime platform, padded with leading // zeros if necessary, and formatted as per the supplied number base. // The string contains no extra decoration. This must be added by the // UI where required. // If the supplied address is invalid, the server will return a // string of the correct size, but filled with question-mark ('?') // characters. define open generic address-to-string (server :: , address :: , #key format :: ) => (s :: ); define method address-to-string (project :: , address :: , #key format :: = #"hexadecimal") => (s :: ) let server = choose-server(project, address); address-to-string(server, address, format: format); end method; ///// STRING-TO-ADDRESS // Synopsis: Converts a string into an abstract address. // Inputs: // server - The backend dispatching object. // str - A string representing a numeric value which needs to // be converted to a runtime address. // format - The format (number base) within which the string // should be interpreted by the server. // Outputs: // addr - An instance of corresponding to // the supplied string, assuming success. (See note). // Note: // This is not a parsing function. For a string that is not well-formed, // the address returned may be invalid, or otherwise nonsensical. // Parsing should be performed by the UI, which should also undertake // to strip away any extra decoration that it might require in order // to determine the number base (eg. "#x"). define open generic string-to-address (server :: , str :: , #key format :: ) => (addr :: ); define method string-to-address (project :: , str :: , #key format :: = #"hexadecimal") => (addr :: ) // Can't use choose-server here, since there is no incoming env object // to dispatch on? let server = project.project-application; (server & string-to-address(server, str, format: format)) | $invalid-address-object end method; ///// ADDRESS-APPLICATION-OBJECT // Synopsis: Converts an abstract address to a more specific application // object where possible. (Eg. if the address corresponds // exactly to a dylan object, then the dylan object will be // returned). // Inputs: // server - The backend dispatching object. // addr - The address to be converted. // Outputs: // obj - An instance of , possibly a // . If the address is not valid, then // it may just be returned unchanged, which is to contract // since is itself a subclass of // . define open generic address-application-object (server :: , addr :: ) => (obj :: ); define method address-application-object (project :: , addr :: ) => (obj :: ) let server = choose-server(project, addr); (server & address-application-object(server, addr)) | $invalid-address-object end method; ///// APPLICATION-OBJECT-ADDRESS // Synopsis: Converts an application object to an address where possible. // Inputs: // server - The backend dispatching object. // obj - The application object to be converted. // Outputs: // addr - An instance of that most directly // corresponds to the original application object. // (Eg. direct conversion from a dylan pointer into an // address). // For application objects that have no meaningful // address, this will return $invalid-address-object. // In most cases, it's clear what the "address" of an application // object is, since it's value is likely to be a pointer. However, // there are some special cases, and the behaviour of this protocol // for those cases is given below: // - Returns the "base address" of the component. // ie. The address at which it is loaded into // memory. (It is assumed that such an address is // both meaningful and obtainable for all // platforms). // - Returns the "frame pointer" of the stack // frame, if it can be determined. define open generic application-object-address (server :: , object :: ) => (address :: false-or()); define method application-object-address (project :: , object :: ) => (addr :: false-or()) let server = project.project-application; server & application-object-address(server, object) end method application-object-address; ///// INDIRECT-ADDRESS // Synopsis: Indirects through an address to generate a new address. // Inputs: // server - The backend dispatching object. // addr - The address through which to perform the indirection. // Outputs: // i-addr - The address object obtained by indirecting through // the original address. // It is entirely possible for this address to be invalid, // and this will certainly be the case if the original // address is invalid. define open generic indirect-address (server :: , addr :: ) => (i-addr :: ); define method indirect-address (project :: , addr :: ) => (i-addr :: ); let server = choose-server(project, addr); (server & indirect-address(server, addr)) | $invalid-address-object end method; ///// INDEXED-ADDRESS // Synopsis: Adds an indexed-offset to a base address. // Inputs: // server - The project dispatching context // addr - The base address. // index - An integer used as the index. // size - An instance of . The implementation // will multiply the index by the appropriate factor according // to this. The default is #"word". // Outputs: // i-addr - The indexed address. define open generic indexed-address (server :: , addr :: , i :: , #key size :: ) => (i-addr :: ); define method indexed-address (project :: , addr :: , i :: , #key size :: = #"word") => (i-addr :: ); let server = choose-server(project, addr); (server & indexed-address(server, addr, i, size: size)) | $invalid-address-object end method; ///// ADDRESS-READ-MEMORY-CONTENTS // Synopsis: Import a block of memory contents starting at the supplied // address, and return the contents as formatted strings. Also // returns the address that immediately follows the block that // has been read. // Inputs: // server - The backend dispatching object. // addr - The address at which to base the import. // size - The granularity at which to read data, defaults // to #"word" (the runtime platform word-size). // format - The format directive for the imported data. // from-index - An array index, interpreted according to the 'size' // parameter, from which to read the first object. // Defaults to zero. // to-index - The index at which to read the last object. This // defaults to 7. define open generic address-read-memory-contents (server :: , addr :: , #key size :: , format :: , from-index :: , to-index :: ) => (printable-strings :: , nxt :: ); define method address-read-memory-contents (project :: , addr :: , #key size :: = #"word", format :: = #"hexadecimal", from-index :: = 0, to-index :: = 7) => (printable-strings :: , nxt :: ) let server = choose-server(project, addr); if (server) address-read-memory-contents(server, addr, format: format, from-index: from-index, to-index: to-index, size: size) else values(#[], $invalid-address-object) end if end method address-read-memory-contents; ///// ADDRESS-READ-APPLICATION-OBJECT // Synopsis: Import an application object from an address. // Inputs: // server - The backend dispatching object. // addr - The address at which to base the import. // Outputs: // obj - Returns the imported application object, or #f if the // import fails. define open generic address-read-application-object (server :: , addr :: ) => (obj :: false-or()); define method address-read-application-object (project :: , addr :: ) => (obj :: false-or()) let server = choose-server(project, addr); server & address-read-application-object(server, addr); end method;