From 5f5ab54810e979f230e4410fc4805c36abfe6dc1 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Tue, 22 Sep 2009 00:36:24 +0000 Subject: SCI: Add new type SegmentRef which ultimately will allow us to distinguish between raw and 'reg_t' memory blocks in client code svn-id: r44244 --- engines/sci/console.cpp | 9 ++-- engines/sci/engine/seg_manager.cpp | 17 ++++---- engines/sci/engine/seg_manager.h | 3 +- engines/sci/engine/segment.cpp | 84 +++++++++++++++++++++++--------------- engines/sci/engine/segment.h | 30 ++++++++++---- 5 files changed, 89 insertions(+), 54 deletions(-) (limited to 'engines/sci') diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index e88efe4f31..0f651709b9 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -1951,7 +1951,8 @@ bool Console::cmdViewReference(int argc, const char **argv) { break; case KSIG_REF: { int size; - byte *block = _vm->_gamestate->segMan->dereference(reg, &size); + const SegmentRef block = _vm->_gamestate->segMan->dereference(reg); + size = block.maxSize; DebugPrintf("raw data\n"); @@ -1966,7 +1967,7 @@ bool Console::cmdViewReference(int argc, const char **argv) { if (reg_end.segment != 0) DebugPrintf("Block size less than or equal to %d\n", size); - Common::hexdump(block, size, 16, 0); + Common::hexdump(block.raw, size, 16, 0); } break; case KSIG_ARITHMETIC: @@ -2248,8 +2249,8 @@ bool Console::cmdDissassembleAddress(int argc, const char **argv) { return true; } - _vm->_gamestate->segMan->dereference(vpc, &size); - size += vpc.offset; // total segment size + SegmentRef ref = _vm->_gamestate->segMan->dereference(vpc); + size = ref.maxSize + vpc.offset; // total segment size for (int i = 2; i < argc; i++) { if (!scumm_stricmp(argv[i], "bwt")) diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp index 6449272bdc..e7e8d4197b 100644 --- a/engines/sci/engine/seg_manager.cpp +++ b/engines/sci/engine/seg_manager.cpp @@ -863,29 +863,30 @@ Hunk *SegManager::alloc_Hunk(reg_t *addr) { return &(table->_table[offset]); } -byte *SegManager::dereference(reg_t pointer, int *size) { +SegmentRef SegManager::dereference(reg_t pointer) { + SegmentRef ret; + if (!pointer.segment || (pointer.segment >= _heap.size()) || !_heap[pointer.segment]) { // This occurs in KQ5CD when interacting with certain objects warning("Attempt to dereference invalid pointer %04x:%04x", PRINT_REG(pointer)); - return NULL; /* Invalid */ + return ret; /* Invalid */ } SegmentObj *mobj = _heap[pointer.segment]; - return mobj->dereference(pointer, size); + return mobj->dereference(pointer); } static void *_kernel_dereference_pointer(SegManager *segMan, reg_t pointer, int entries) { - int maxsize; - void *retval = segMan->dereference(pointer, &maxsize); + SegmentRef ret = segMan->dereference(pointer); - if (!retval) + if (!ret.raw) return NULL; - if (entries > maxsize) { + if (entries > ret.maxSize) { warning("Trying to dereference pointer %04x:%04x beyond end of segment", PRINT_REG(pointer)); return NULL; } - return retval; + return ret.raw; } diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h index 8c6676d0ec..61b0c76e2e 100644 --- a/engines/sci/engine/seg_manager.h +++ b/engines/sci/engine/seg_manager.h @@ -279,10 +279,9 @@ public: /** * Dereferences a raw memory pointer * @param[in] reg The reference to dereference - * @param[out] size (optional) The theoretical maximum size * @return The data block referenced */ - byte *dereference(reg_t reg, int *size); + SegmentRef dereference(reg_t pointer); /** * Dereferences a heap pointer pointing to raw memory. diff --git a/engines/sci/engine/segment.cpp b/engines/sci/engine/segment.cpp index 80027dbb39..7d2889aefc 100644 --- a/engines/sci/engine/segment.cpp +++ b/engines/sci/engine/segment.cpp @@ -214,79 +214,97 @@ int16 Script::getHeap(uint16 offset) const { // return (_buf[offset] | (_buf[offset+1]) << 8); } -byte *SegmentObj::dereference(reg_t pointer, int *size) { +SegmentRef SegmentObj::dereference(reg_t pointer) { error("Error: Trying to dereference pointer %04x:%04x to inappropriate segment", PRINT_REG(pointer)); - return NULL; + return SegmentRef(); } bool Script::isValidOffset(uint16 offset) const { return offset < _bufSize; } -byte *Script::dereference(reg_t pointer, int *size) { +SegmentRef Script::dereference(reg_t pointer) { if (pointer.offset > _bufSize) { - warning("Attempt to dereference invalid pointer %04x:%04x into script segment (script size=%d)\n", + warning("Attempt to dereference invalid pointer %04x:%04x into script segment (script size=%d)", PRINT_REG(pointer), (uint)_bufSize); - return NULL; + return SegmentRef(); } - if (size) - *size = _bufSize - pointer.offset; - return _buf + pointer.offset; + + SegmentRef ret; + ret.isRaw = true; + ret.maxSize = _bufSize - pointer.offset; + ret.raw = _buf + pointer.offset; + return ret; } bool LocalVariables::isValidOffset(uint16 offset) const { return offset < _locals.size() * sizeof(reg_t); } -byte *LocalVariables::dereference(reg_t pointer, int *size) { - if (size) - *size = _locals.size() * sizeof(reg_t); - +SegmentRef LocalVariables::dereference(reg_t pointer) { // FIXME: The following doesn't seem to be endian safe. // To fix this, we'd have to always treat the reg_t // values stored here as in the little endian format. - byte *base = (byte *)&_locals[0]; - return base + pointer.offset; + // Anyway, generate a warning for now to see if this ever + // happens. + // One has to wonder whether we return the right value anyway. + // Here are three potential options: + // 1: ((byte *)&_locals[0]) + pointer.offset + // 2: ((byte *)&_locals[pointer.offset/2]) + (pointer.offset % 2) + // 3: ((byte *)&_locals[pointer.offset]) + // So which one is correct? :) + if (pointer.offset & 1) + warning("LocalVariables::dereference: Odd offset in pointer %04x:%04x", PRINT_REG(pointer)); + + SegmentRef ret; + ret.isRaw = false; // reg_t based data! + ret.maxSize = _locals.size() * sizeof(reg_t); + ret.raw = (byte *)&_locals[0] + pointer.offset; + return ret; } bool DataStack::isValidOffset(uint16 offset) const { return offset < _capacity * sizeof(reg_t); } -byte *DataStack::dereference(reg_t pointer, int *size) { - if (size) - *size = _capacity * sizeof(reg_t); - - byte *base = (byte *)_entries; - return base + pointer.offset; +SegmentRef DataStack::dereference(reg_t pointer) { + SegmentRef ret; + ret.isRaw = false; // reg_t based data! + ret.maxSize = _capacity * sizeof(reg_t); + // FIXME: Is this correct? See comment in LocalVariables::dereference + ret.raw = (byte *)_entries + pointer.offset; + return ret; } bool DynMem::isValidOffset(uint16 offset) const { return offset < _size; } -byte *DynMem::dereference(reg_t pointer, int *size) { - if (size) - *size = _size; - - byte *base = (byte *)_buf; - return base + pointer.offset; +SegmentRef DynMem::dereference(reg_t pointer) { + SegmentRef ret; + ret.isRaw = true; + ret.maxSize = _size; + ret.raw = _buf + pointer.offset; + return ret; } bool SystemStrings::isValidOffset(uint16 offset) const { return offset < SYS_STRINGS_MAX && !strings[offset]._name.empty(); } -byte *SystemStrings::dereference(reg_t pointer, int *size) { - if (size) - *size = strings[pointer.offset].max_size; +SegmentRef SystemStrings::dereference(reg_t pointer) { + SegmentRef ret; + ret.isRaw = false; // FIXME: Raw or not raw? the sys strings code is totally incoherent in this regard + ret.maxSize = strings[pointer.offset].max_size; if (isValidOffset(pointer.offset)) - return (byte *)(strings[pointer.offset].value); + ret.raw = (byte *)(strings[pointer.offset].value); + else { + // This occurs in KQ5CD when interacting with certain objects + warning("Attempt to dereference invalid pointer %04x:%04x", PRINT_REG(pointer)); + } - // This occurs in KQ5CD when interacting with certain objects - warning("Attempt to dereference invalid pointer %04x:%04x", PRINT_REG(pointer)); - return NULL; + return ret; } diff --git a/engines/sci/engine/segment.h b/engines/sci/engine/segment.h index 81da9c2488..1f446957d5 100644 --- a/engines/sci/engine/segment.h +++ b/engines/sci/engine/segment.h @@ -34,6 +34,23 @@ namespace Sci { +struct SegmentRef { + bool isRaw; ///! true if data is raw, false if it is a reg_t sequence + union { + byte *raw; + reg_t *reg; + }; + int maxSize; ///! number of available bytes + // TODO: Add this? + //reg_t pointer; // Original pointer + + // TODO: Add this? + //SegmentType type; + + SegmentRef() : isRaw(true), raw(0), maxSize(0) {} +}; + + enum SegmentType { SEG_TYPE_INVALID = 0, SEG_TYPE_SCRIPT = 1, @@ -73,10 +90,9 @@ public: /** * Dereferences a raw memory pointer. * @param reg reference to dereference - * @param size if not NULL, set to the theoretical maximum size of the referenced data block * @return the data block referenced */ - virtual byte *dereference(reg_t pointer, int *size); + virtual SegmentRef dereference(reg_t pointer); /** * Finds the canonic address associated with sub_reg. @@ -161,7 +177,7 @@ public: } virtual bool isValidOffset(uint16 offset) const; - virtual byte *dereference(reg_t pointer, int *size); + virtual SegmentRef dereference(reg_t pointer); virtual void saveLoadWithSerializer(Common::Serializer &ser); }; @@ -176,7 +192,7 @@ public: } virtual bool isValidOffset(uint16 offset) const; - virtual byte *dereference(reg_t pointer, int *size); + virtual SegmentRef dereference(reg_t pointer); virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr); virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note); @@ -309,7 +325,7 @@ public: bool init(int script_nr, ResourceManager *resMan); virtual bool isValidOffset(uint16 offset) const; - virtual byte *dereference(reg_t pointer, int *size); + virtual SegmentRef dereference(reg_t pointer); virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr); virtual void freeAtAddress(SegManager *segMan, reg_t sub_addr); virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note); @@ -467,7 +483,7 @@ public: } virtual bool isValidOffset(uint16 offset) const; - virtual byte *dereference(reg_t pointer, int *size); + virtual SegmentRef dereference(reg_t pointer); virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr); virtual void listAllOutgoingReferences(reg_t object, void *param, NoteCallback note); @@ -624,7 +640,7 @@ public: } virtual bool isValidOffset(uint16 offset) const; - virtual byte *dereference(reg_t pointer, int *size); + virtual SegmentRef dereference(reg_t pointer); virtual reg_t findCanonicAddress(SegManager *segMan, reg_t sub_addr); virtual void listAllDeallocatable(SegmentId segId, void *param, NoteCallback note); -- cgit v1.2.3