Commit 88ae7e18 authored by Jeffrey Lee's avatar Jeffrey Lee Committed by ROOL

Add cross-check support to heaptest

Version 6.26. Tagged as 'Kernel-6_26'
parent b954559e
...@@ -29,20 +29,40 @@ ...@@ -29,20 +29,40 @@
/* Whether to use the XOS_Heap SWI or the local copy of the heap code */ /* Whether to use the XOS_Heap SWI or the local copy of the heap code */
#define USE_LOCAL_OSHEAP #define USE_LOCAL_OSHEAP
/* Cross-check against XOS_Heap SWI (expects 100% identical behaviour) */
//#define CROSSCHECK
/* Cross-check against local heap code instead of XOS_Heap */
//#define CROSSCHECK_LOCAL
/* Maximum number of allocations to make */ /* Maximum number of allocations to make */
#define MAX_ALLOCS 1024 #define MAX_ALLOCS 1024
#define VBIT (1<<28) #if defined(CROSSCHECK_LOCAL) && !defined(CROSSCHECK)
#define CROSSCHECK
#ifdef USE_LOCAL_OSHEAP
extern _kernel_oserror *CallHeap(_kernel_swi_regs *r);
#else
#define CallHeap(R) _kernel_swi(OS_Heap,R,R)
#endif #endif
static _kernel_oserror *CallOSHeap(_kernel_swi_regs *r)
{
return _kernel_swi(OS_Heap,r,r);
}
extern _kernel_oserror *CallMyHeap(_kernel_swi_regs *r);
typedef _kernel_oserror *(*heapfunc_t)(_kernel_swi_regs *r);
typedef struct {
uint32_t *heap; /* Main heap */
uint32_t *backup; /* Backup copy of heap */
heapfunc_t heapfunc;
int calls;
} heap_t;
/* Workspace */ /* Workspace */
static uint32_t *heap=NULL; /* Main heap */ static heap_t heap; /* Main test heap */
static uint32_t *backup=NULL; /* Backup copy of heap */ #ifdef CROSSCHECK
static heap_t crosscheck; /* Secondary heap if cross-checking against OS */
#endif
static uint32_t allocsize=0; /* Heap memory block size */ static uint32_t allocsize=0; /* Heap memory block size */
static uint32_t *usedspace=NULL; /* Bitmap of used space; 1 bit per word */ static uint32_t *usedspace=NULL; /* Bitmap of used space; 1 bit per word */
static uint32_t seed=0; /* RNG seed */ static uint32_t seed=0; /* RNG seed */
...@@ -51,22 +71,44 @@ static uint32_t numblocks=0; /* Number of blocks currently allocated */ ...@@ -51,22 +71,44 @@ static uint32_t numblocks=0; /* Number of blocks currently allocated */
static uint32_t blocks[MAX_ALLOCS]; /* Offsets of blocks within heap */ static uint32_t blocks[MAX_ALLOCS]; /* Offsets of blocks within heap */
static uint32_t currentop = 0; /* Current heap operation */ static uint32_t currentop = 0; /* Current heap operation */
static uint32_t opsleft = 0; /* Number of ops left */ static uint32_t opsleft = 0; /* Number of ops left */
static _kernel_swi_regs r; static _kernel_swi_regs regs;
static _kernel_swi_regs last; static _kernel_swi_regs last;
#ifdef CROSSCHECK
static _kernel_swi_regs cr;
#endif
/* Utility functions */ /* Utility functions */
static void init(void) static _kernel_oserror *CallHeap(heap_t *h, _kernel_swi_regs *r)
{ {
srand(seed); memcpy(h->backup,h->heap,allocsize);
printf("Seed %08x alloc size %08x\n",seed,allocsize); r->r[1] = (int) h->heap;
heap = (uint32_t *) malloc(allocsize); h->calls++;
backup = (uint32_t *) malloc(allocsize); return h->heapfunc(r);
/* Used space map */ }
usedspace = (uint32_t *) malloc(((allocsize+31*4)>>7)<<2);
memset(usedspace,0,((allocsize+31*4)>>7)<<2); static void init(heap_t *h, heapfunc_t heapfunc)
memset(heap,0,allocsize); {
memset(backup,0,allocsize); _kernel_swi_regs r;
h->heapfunc = heapfunc;
/* Make heap 4K aligned */
h->heap = (uint32_t *) (((uint32_t) malloc(allocsize+4096)+4095)&0xfffff000);
/* Same for backup */
h->backup = (uint32_t *) (((uint32_t) malloc(allocsize+4096)+4095)&0xfffff000);
memset(h->heap,0,allocsize);
memset(h->backup,0,allocsize);
/* Initialise heap */
r.r[0] = HeapReason_Init;
r.r[3] = allocsize;
_kernel_oserror *err = CallHeap(h,&r);
if(err)
{
fprintf(stderr,"Heap initialise failed! %s\n",err->errmess);
exit(1);
}
} }
static uint32_t getrand(uint32_t max) static uint32_t getrand(uint32_t max)
...@@ -77,7 +119,7 @@ static uint32_t getrand(uint32_t max) ...@@ -77,7 +119,7 @@ static uint32_t getrand(uint32_t max)
static void dumpheap(uint32_t *h) static void dumpheap(uint32_t *h)
{ {
fprintf(stderr,"heap @ %p:\nmag %x\nfree %x\nbase %x\nend %x\n",h,h[0],h[1],h[2],h[3]); fprintf(stderr,"heap @ %p:\nmagic %x\nfree %x\nbase %x\nend %x\n",h,h[0],h[1],h[2],h[3]);
uint32_t free = h[1]; uint32_t free = h[1];
uint32_t next = 16; uint32_t next = 16;
if(free) if(free)
...@@ -86,12 +128,12 @@ static void dumpheap(uint32_t *h) ...@@ -86,12 +128,12 @@ static void dumpheap(uint32_t *h)
{ {
if(free > next) if(free > next)
{ {
fprintf(stderr,"allocs between %x and %x:\n",next,free); fprintf(stderr," allocs between %x and %x:\n",next,free);
do { do {
fprintf(stderr,"%x: alloc size %x\n",next,h[next>>2]); fprintf(stderr," %x: alloc size %x\n",next,h[next>>2]);
if((h[next>>2] > h[2]) || (h[next>>2]+next > h[2]) || (h[next>>2]&3) || !h[next>>2]) if((h[next>>2] > h[2]) || (h[next>>2]+next > h[2]) || (h[next>>2]&3) || !h[next>>2])
{ {
fprintf(stderr,"bad block, skipping rest\n"); fprintf(stderr," bad block, skipping rest\n");
break; break;
} }
next += h[next>>2]; next += h[next>>2];
...@@ -99,47 +141,47 @@ static void dumpheap(uint32_t *h) ...@@ -99,47 +141,47 @@ static void dumpheap(uint32_t *h)
if(free!=next) if(free!=next)
fprintf(stderr,"alloc mismatch! next=%x\n",next); fprintf(stderr,"alloc mismatch! next=%x\n",next);
} }
fprintf(stderr,"%x: free size %x next %x\n",free,h[(free+4)>>2],h[free>>2]); fprintf(stderr," %x: free size %x next %x\n",free,h[(free+4)>>2],h[free>>2]);
if(h[(free+4)>>2] == h[free>>2]) if(h[(free+4)>>2] == h[free>>2])
fprintf(stderr,"consecutive free blocks!\n"); fprintf(stderr," consecutive free blocks!\n");
next = free+h[(free+4)>>2]; next = free+h[(free+4)>>2];
if((h[free>>2] & 3) || (h[free>>2] >= h[2]) || (h[free>>2]+free >= h[2])) if((h[free>>2] & 3) || (h[free>>2] >= h[2]) || (h[free>>2]+free >= h[2]))
{ {
fprintf(stderr,"bad next ptr\n"); fprintf(stderr," bad next ptr\n");
return; return;
} }
if((h[(free+4)>>2] & 3) || (h[(free+4)>>2] >= h[2]) || (h[(free+4)>>2]+free >= h[2])) if((h[(free+4)>>2] & 3) || (h[(free+4)>>2] >= h[2]) || (h[(free+4)>>2]+free >= h[2]))
{ {
fprintf(stderr,"bad size\n"); fprintf(stderr," bad size\n");
return; return;
} }
if(!h[free>>2]) if(!h[free>>2])
{ {
fprintf(stderr,"end of free list\n"); fprintf(stderr," end of free list\n");
break; break;
} }
free = free+h[free>>2]; free = free+h[free>>2];
if(free<next) if(free<next)
{ {
fprintf(stderr,"next free is inside current?\n"); fprintf(stderr," next free is inside current?\n");
return; return;
} }
} }
if(free > h[2]) if(free > h[2])
{ {
fprintf(stderr,"free list extends beyond heap end\n"); fprintf(stderr," free list extends beyond heap end\n");
} }
if(next > h[2]) if(next > h[2])
{ {
fprintf(stderr,"next ptr beyond heap end\n"); fprintf(stderr," next ptr beyond heap end\n");
} }
fprintf(stderr,"end allocs:\n"); fprintf(stderr,"end allocs:\n");
while(next < h[2]) while(next < h[2])
{ {
fprintf(stderr,"%x: alloc size %x\n",next,h[next>>2]); fprintf(stderr," %x: alloc size %x\n",next,h[next>>2]);
if((h[next>>2] > h[2]) || (h[next>>2]+next > h[2]) || (h[next>>2]&3) || !h[next>>2]) if((h[next>>2] > h[2]) || (h[next>>2]+next > h[2]) || (h[next>>2]&3) || !h[next>>2])
{ {
fprintf(stderr,"bad block, skipping rest\n"); fprintf(stderr," bad block, skipping rest\n");
return; return;
} }
next += h[next>>2]; next += h[next>>2];
...@@ -212,25 +254,36 @@ static void fail(void) ...@@ -212,25 +254,36 @@ static void fail(void)
fprintf(stderr,"Failed on sequence %d\n",sequence); fprintf(stderr,"Failed on sequence %d\n",sequence);
fprintf(stderr,"Last op registers:\n"); fprintf(stderr,"Last op registers:\n");
for(int i=0;i<5;i++) for(int i=0;i<5;i++)
fprintf(stderr,"r%d = %08x\n",i,last.r[i]); fprintf(stderr," r%d = %08x\n",i,last.r[i]);
fprintf(stderr,"Result registers:\n"); fprintf(stderr,"Result registers:\n");
for(int i=0;i<5;i++) for(int i=0;i<5;i++)
fprintf(stderr,"r%d = %08x\n",i,r.r[i]); fprintf(stderr," r%d = %08x\n",i,regs.r[i]);
#ifdef CROSSCHECK
fprintf(stderr,"Crosscheck result registers:\n");
for(int i=0;i<5;i++)
fprintf(stderr," r%d = %08x\n",i,cr.r[i]);
#endif
fprintf(stderr,"Heap before op:\n"); fprintf(stderr,"Heap before op:\n");
dumpheap(backup); dumpheap(heap.backup);
fprintf(stderr,"Heap after op:\n"); fprintf(stderr,"Heap after op:\n");
dumpheap(heap); dumpheap(heap.heap);
#ifdef CROSSCHECK
fprintf(stderr,"Crosscheck heap before op:\n");
dumpheap(crosscheck.backup);
fprintf(stderr,"Crosscheck heap after op:\n");
dumpheap(crosscheck.heap);
#endif
fprintf(stderr,"Allocated blocks:\n"); fprintf(stderr,"Allocated blocks:\n");
for(uint32_t i=0;i<numblocks;i++) for(uint32_t i=0;i<numblocks;i++)
{ {
fprintf(stderr,"%08x\n",blocks[i]); fprintf(stderr," %08x\n",blocks[i]);
} }
exit(1); exit(1);
} }
static uint32_t blocksize(uint32_t offset) static uint32_t blocksize(uint32_t offset)
{ {
return heap[(offset-4)>>2]; return heap.heap[(offset-4)>>2];
} }
static void tryuse(uint32_t offset) static void tryuse(uint32_t offset)
...@@ -281,33 +334,48 @@ static void tryfree(uint32_t offset) ...@@ -281,33 +334,48 @@ static void tryfree(uint32_t offset)
int main(int argc,char **argv) int main(int argc,char **argv)
{ {
_kernel_oserror *err; _kernel_oserror *err = NULL;
#ifdef CROSSCHECK
_kernel_oserror err2;
#endif
/* TODO - Take parameters from command line */ /* TODO - Take parameters from command line */
_swix(OS_ReadMonotonicTime,_OUT(0),&seed); _swix(OS_ReadMonotonicTime,_OUT(0),&seed);
allocsize = 8*1024; /* 8K is sensible minimum, due to max alignment/boundary used of 2K */ allocsize = 8*1024; /* 8K is sensible minimum, due to max alignment/boundary used of 2K */
init(); printf("Seed %08x alloc size %08x\n",seed,allocsize);
srand(seed);
/* Initialise heap */ /* Used space map */
r.r[0] = HeapReason_Init; usedspace = (uint32_t *) malloc(((allocsize+31*4)>>7)<<2);
r.r[1] = (int) heap; memset(usedspace,0,((allocsize+31*4)>>7)<<2);
r.r[3] = allocsize;
err = CallHeap(&r);
if(err)
{
fprintf(stderr,"Heap initialise failed! %s\n",err->errmess);
exit(1);
}
usedspace[0] = 0xf; usedspace[0] = 0xf;
init(&heap,
#ifdef USE_LOCAL_OSHEAP
CallMyHeap
#else
CallOSHeap
#endif
);
#ifdef CROSSCHECK
init(&crosscheck,
#ifdef CROSSCHECK_LOCAL
CallMyHeap
#else
CallOSHeap
#endif
);
#endif
/* Begin tests */ /* Begin tests */
uint32_t temp,temp2,temp3,temp4,temp5; uint32_t temp,temp2,temp3,temp4,temp5;
while(heapvalid(heap)) while(heapvalid(heap.heap))
{ {
if(!opsleft) if(!opsleft)
{ {
opsleft = getrand(128); opsleft = getrand(128)+1;
switch(getrand(5)) switch(getrand(5))
{ {
case 0: case 0:
...@@ -330,11 +398,10 @@ int main(int argc,char **argv) ...@@ -330,11 +398,10 @@ int main(int argc,char **argv)
if(!(sequence&0xffff)) if(!(sequence&0xffff))
{ {
// printf("."); // printf(".");
dumpheap(heap); dumpheap(heap.heap);
} }
sequence++; sequence++;
r.r[0] = currentop; regs.r[0] = currentop;
memcpy(backup,heap,allocsize);
switch(currentop) switch(currentop)
{ {
case HeapReason_Get: case HeapReason_Get:
...@@ -343,9 +410,9 @@ int main(int argc,char **argv) ...@@ -343,9 +410,9 @@ int main(int argc,char **argv)
opsleft = 0; opsleft = 0;
break; break;
} }
r.r[3] = temp = getrand(allocsize>>5)+1; regs.r[3] = temp = getrand(allocsize>>5)+1;
last = r; last = regs;
err = CallHeap(&r); err = CallHeap(&heap,&regs);
if(err) if(err)
{ {
if(err->errnum != ErrorNumber_HeapFail_Alloc) if(err->errnum != ErrorNumber_HeapFail_Alloc)
...@@ -356,7 +423,7 @@ int main(int argc,char **argv) ...@@ -356,7 +423,7 @@ int main(int argc,char **argv)
} }
else else
{ {
temp2 = blocks[numblocks++] = r.r[2]-((uint32_t)heap); temp2 = blocks[numblocks++] = regs.r[2]-((uint32_t)heap.heap);
if(blocksize(temp2) < temp+4) if(blocksize(temp2) < temp+4)
{ {
fprintf(stderr,"Failed to allocate requested block size: %08x bytes at %08x\n",temp,temp2); fprintf(stderr,"Failed to allocate requested block size: %08x bytes at %08x\n",temp,temp2);
...@@ -372,10 +439,10 @@ int main(int argc,char **argv) ...@@ -372,10 +439,10 @@ int main(int argc,char **argv)
break; break;
} }
temp = getrand(numblocks); temp = getrand(numblocks);
r.r[2] = blocks[temp]+((uint32_t) heap); regs.r[2] = blocks[temp]+((uint32_t) heap.heap);
tryfree(blocks[temp]); /* Must free beforehand */ tryfree(blocks[temp]); /* Must free beforehand */
last = r; last = regs;
err = CallHeap(&r); err = CallHeap(&heap,&regs);
if(err) if(err)
{ {
fprintf(stderr,"Failed freeing block at %08x: %s\n",blocks[temp],err->errmess); fprintf(stderr,"Failed freeing block at %08x: %s\n",blocks[temp],err->errmess);
...@@ -390,13 +457,13 @@ int main(int argc,char **argv) ...@@ -390,13 +457,13 @@ int main(int argc,char **argv)
break; break;
} }
temp = getrand(numblocks); temp = getrand(numblocks);
r.r[2] = blocks[temp]+((uint32_t) heap); regs.r[2] = blocks[temp]+((uint32_t) heap.heap);
temp2 = getrand(allocsize>>4)-(allocsize>>5); temp2 = getrand(allocsize>>4)-(allocsize>>5);
r.r[3] = temp2; regs.r[3] = temp2;
temp3 = blocksize(blocks[temp]); temp3 = blocksize(blocks[temp]);
tryfree(blocks[temp]); /* Must free beforehand */ tryfree(blocks[temp]); /* Must free beforehand */
last = r; last = regs;
err = CallHeap(&r); err = CallHeap(&heap,&regs);
if(err) if(err)
{ {
if(err->errnum != ErrorNumber_HeapFail_Alloc) if(err->errnum != ErrorNumber_HeapFail_Alloc)
...@@ -413,14 +480,14 @@ int main(int argc,char **argv) ...@@ -413,14 +480,14 @@ int main(int argc,char **argv)
} }
else else
{ {
if(r.r[2] && (r.r[2] != 0xffffffff)) if(regs.r[2] && (regs.r[2] != 0xffffffff))
{ {
if((int) (temp3+temp2) <= 4) if((int) (temp3+temp2) <= 4)
{ {
fprintf(stderr,"Resized block was kept when it should have been freed: block %08x by %08x\n",blocks[temp],(int) temp2); fprintf(stderr,"Resized block was kept when it should have been freed: block %08x by %08x\n",blocks[temp],(int) temp2);
fail(); fail();
} }
blocks[temp] = r.r[2]-((uint32_t)heap); blocks[temp] = regs.r[2]-((uint32_t)heap.heap);
tryuse(blocks[temp]); tryuse(blocks[temp]);
if((blocksize(blocks[temp])-(temp3+temp2)) > 11) if((blocksize(blocks[temp])-(temp3+temp2)) > 11)
{ {
...@@ -446,19 +513,19 @@ int main(int argc,char **argv) ...@@ -446,19 +513,19 @@ int main(int argc,char **argv)
opsleft = 0; opsleft = 0;
break; break;
} }
r.r[3] = temp = getrand(allocsize>>4)+1; regs.r[3] = temp = getrand(allocsize>>4)+1;
temp2 = 4<<getrand(9); /* Max 2K alignment */ temp2 = 4<<getrand(9); /* Max 2K alignment */
temp3 = temp2*(1<<getrand(5)); temp3 = temp2*(1<<getrand(5));
if(temp3 > 4096) /* Max 2K boundary */ if(temp3 > 4096) /* Max 2K boundary */
temp3 = 2048; temp3 = 2048;
if(temp3 < temp) if(temp3 < temp)
temp3 = 0; temp3 = 0;
r.r[2] = temp2; regs.r[2] = temp2;
r.r[4] = temp3; regs.r[4] = temp3;
r.r[5] = 0; regs.r[5] = 0;
temp5 = (currentop == HeapReason_GetAligned ? r.r[1] : r.r[5]); temp5 = (currentop == HeapReason_GetAligned ? regs.r[1] : regs.r[5]);
last = r; last = regs;
err = CallHeap(&r); err = CallHeap(&heap,&regs);
if(err) if(err)
{ {
if(err->errnum != ErrorNumber_HeapFail_Alloc) if(err->errnum != ErrorNumber_HeapFail_Alloc)
...@@ -469,7 +536,7 @@ int main(int argc,char **argv) ...@@ -469,7 +536,7 @@ int main(int argc,char **argv)
} }
else else
{ {
temp4 = blocks[numblocks++] = r.r[2]-((uint32_t) heap); temp4 = blocks[numblocks++] = regs.r[2]-((uint32_t) heap.heap);
if(blocksize(temp4) < temp+4) if(blocksize(temp4) < temp+4)
{ {
fprintf(stderr,"Failed to allocate requested block size: %08x bytes at alignment %08x boundary %08x at %08x\n",temp,temp2,temp3,temp4); fprintf(stderr,"Failed to allocate requested block size: %08x bytes at alignment %08x boundary %08x at %08x\n",temp,temp2,temp3,temp4);
...@@ -490,6 +557,70 @@ int main(int argc,char **argv) ...@@ -490,6 +557,70 @@ int main(int argc,char **argv)
} }
break; break;
} }
#ifdef CROSSCHECK
if (opsleft)
{
if (heap.calls != crosscheck.calls+1)
{
fprintf(stderr,"Heaptest failure: Wrong heap call counts\n");
fail();
}
if (memcmp(heap.backup,crosscheck.heap,allocsize))
{
fprintf(stderr,"Heaptest failure: Heap & crosscheck are unexpectedly out of sync\n");
fail();
}
cr = last;
if((currentop == HeapReason_Free) || (currentop == HeapReason_ExtendBlock))
{
cr.r[2] += ((int)crosscheck.heap) - ((int)heap.heap);
}
if (err != NULL)
{
err2 = *err;
}
else
{
err2.errnum = 0;
err2.errmess[0] = 0;
}
err = CallHeap(&crosscheck,&cr);
if(err != NULL)
{
if((err->errnum != err2.errnum) || strcmp(err->errmess,err2.errmess))
{
fprintf(stderr,"Crosscheck failure: Error %08x %s\nCrosscheck %08x %s\n",err2.errnum,err2.errmess,err->errnum,err->errmess);
fail();
}
}
else
{
if(err2.errnum)
{
fprintf(stderr,"Crosscheck failure: Error %08x %s\nCrosscheck no error\n",err2.errnum,err2.errmess);
fail();
}
/* R2 is the only result register we care about */
if ((currentop == HeapReason_Get) || (currentop == HeapReason_ExtendBlock) || (currentop == HeapReason_GetAligned) || (currentop == HeapReason_GetSkewAligned))
{
if ((currentop == HeapReason_ExtendBlock) && (regs.r[2] == -1) && (cr.r[2] == -1))
{
/* OK */
}
else if ((regs.r[2] - (int)heap.heap) != (cr.r[2] - (int)crosscheck.heap))
{
fprintf(stderr,"Crosscheck failure: Block offset %08x crosscheck %08x\n",regs.r[2] - (int)heap.heap,cr.r[2] - (int)crosscheck.heap);
fail();
}
}
}
if (memcmp(heap.heap,crosscheck.heap,allocsize))
{
fprintf(stderr,"Crosscheck failure: Heaps different\n");
fail();
}
}
#endif
if(opsleft) if(opsleft)
opsleft--; opsleft--;
} }
......
...@@ -84,8 +84,8 @@ HeapBackgroundError % 256 ...@@ -84,8 +84,8 @@ HeapBackgroundError % 256
; C interface ; C interface
EXPORT CallHeap EXPORT CallMyHeap
CallHeap ROUT CallMyHeap ROUT
; r0 = _kernel_swi_regs ptr for input/output ; r0 = _kernel_swi_regs ptr for input/output
; Returns error ptr in r0 ; Returns error ptr in r0
Push "r0,r4-r11,lr" Push "r0,r4-r11,lr"
......
...@@ -9,12 +9,12 @@ ...@@ -9,12 +9,12 @@
GBLS Module_ApplicationDate GBLS Module_ApplicationDate
GBLS Module_HelpVersion GBLS Module_HelpVersion
GBLS Module_ComponentName GBLS Module_ComponentName
Module_MajorVersion SETS "6.25" Module_MajorVersion SETS "6.26"
Module_Version SETA 625 Module_Version SETA 626
Module_MinorVersion SETS "" Module_MinorVersion SETS ""
Module_Date SETS "20 Oct 2019" Module_Date SETS "05 Nov 2019"
Module_ApplicationDate SETS "20-Oct-19" Module_ApplicationDate SETS "05-Nov-19"
Module_ComponentName SETS "Kernel" Module_ComponentName SETS "Kernel"
Module_FullVersion SETS "6.25" Module_FullVersion SETS "6.26"
Module_HelpVersion SETS "6.25 (20 Oct 2019)" Module_HelpVersion SETS "6.26 (05 Nov 2019)"
END END
/* (6.25) /* (6.26)
* *
* This file is automatically maintained by srccommit, do not edit manually. * This file is automatically maintained by srccommit, do not edit manually.
* *
*/ */
#define Module_MajorVersion_CMHG 6.25 #define Module_MajorVersion_CMHG 6.26
#define Module_MinorVersion_CMHG #define Module_MinorVersion_CMHG
#define Module_Date_CMHG 20 Oct 2019 #define Module_Date_CMHG 05 Nov 2019
#define Module_MajorVersion "6.25" #define Module_MajorVersion "6.26"
#define Module_Version 625 #define Module_Version 626
#define Module_MinorVersion "" #define Module_MinorVersion ""
#define Module_Date "20 Oct 2019" #define Module_Date "05 Nov 2019"
#define Module_ApplicationDate "20-Oct-19" #define Module_ApplicationDate "05-Nov-19"
#define Module_ComponentName "Kernel" #define Module_ComponentName "Kernel"
#define Module_FullVersion "6.25" #define Module_FullVersion "6.26"
#define Module_HelpVersion "6.25 (20 Oct 2019)" #define Module_HelpVersion "6.26 (05 Nov 2019)"
#define Module_LibraryVersionInfo "6:25" #define Module_LibraryVersionInfo "6:26"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment