Many kinds of internal OllyDbg data consist of homogenous elements that has start and final address and do not overlap with each other. Good example is the table of memory blocks. Breakpoints may be treated as elements occupying 1 byte in memory space of debugged program. Threads exist in the address space of thread identifiers and also occupy 1 address of this space. Elements usually can be displayed in some window and sorted using some criterium. Set of such elements is called sorted data.
OllyDbg implements a powerful set of functions that allow easy operations with sorted data, like initilaization, adding or replacing of elements, removing of elements or address ranges, sorting, search and so on. OllyDbg automatically allocates new memory for sorted data if necessary.
Elements of sorted data are always kept sorted by address in a contiguous buffer. This allows for simple and extremely fast binary search. Adding new data is, of course, not so easy and can take significant time. Weighted binary trees may look as a better solution, but in our case data is read much more frequently than added to the table. If you sort data by method other than increasing addresses, OllyDbg simply creates additional array of indexes pointing to data elements.
All elements of sorted data begin with a standard 12-byte header:
typedef struct t_sortheader { // Header of sorted data field
ulong addr; // Base address of the element
ulong size; // Size occupied by element in address space
ulong type; // Type of data element, TY_xxx
} t_sortheader;
Please don't mix the size specified in this header and physical size of the element. They belong to different address spaces! Size in header is the size of piece of virtual address space described by sorted data and usually belongs to debugged program. Physical size of element is the size of memory ocuppied by element in the OllyDbg's memory. All elements have same physical size necessary to fit all the characteristics and descriptions of the described object; size in header is simply one (albeit most important) of the object's characteristics and may be different for each object.
In most cases sorted data functions ignore type and you may use it as you want. Only Deletenonconfirmedsorteddata checks for bit TY_CONFIRMED and removes at once all elements where this bit is not set (a very fast way to get rid of unnecessary elements). Standard header can be followed by any additional fields. OllyDbg does not aligns data elements; to assure effective memory access, make physical size of element a multiple of 4 bytes.
There is a special kind of sorted data called autoarrangeable. Autoarrangeable data assumes that address of the element is simply its 0-based ordinal number in the data array and size occupied by element in address space is always 1. Even in this case, elements must begin with valid header. Addsorteddata always inserts new items to autoarrangeable data and never replaces existing.
To create your own table of sorted data, first of all you must allocate table descriptor (structure of type t_sorted) and initialize all its fields to 0. Then you call Createsorteddata to initialize table and allocate data buffers. After initialization, you can use all sorted data functions to change or retrieve data. Do not modify items of table descriptor directly, this may lead to severe data integrity problems!
Index array is allocated only if valid sortfunc is specified. To assure that sorted data is valid and correctly initialized, check that data pointer is not NULL. If n is 0, table is empty (but is not necessarily initialized).
Table version increments by 1 each time table of sorted data changes. This allows for easy implementation of small cache: if version is not changed, previously fetched data is still valid. In any imaginable application, wraparound of 32-bit variable is impossible. Createsorteddata initializes version to 1, so set cache version to 0 to indicate that cache is invalid.
If sorted is 0, index table was not updated after last modification of the data. To force sorting, call Sortsorteddata. If data is already sorted, Sortsorteddata returns immediately.
int Createsorteddata(t_sorted *sd,char *name,int itemsize,int nmax,SORTFUNC *sortfunc,DESTFUNC *destfunc);
void Destroysorteddata(t_sorted *sd);
void *Addsorteddata (t_sorted *sd,void *item);
void Deletesorteddata(t_sorted *sd,ulong addr);
void Deletesorteddatarange(t_sorted *sd,ulong addr0,ulong addr1);
int Deletenonconfirmedsorteddata(t_sorted *sd);
void* Findsorteddata(t_sorted *sd,ulong addr);
void* Findsorteddatarange(t_sorted *sd,ulong addr0,ulong addr1);
int Findsorteddataindex(t_sorted *sd,ulong addr0,ulong addr1);
int Sortsorteddata(t_sorted *sd,int sort);
void* Getsortedbyselection(t_sorted *sd,int index);