ODBG2_Pluginsaveudd

Optional plugin callback function, allows plugin to save module-related data to the .udd file.

In the OllyDbg v1.xx plugin authors were forced (or at least expected) to register unique .udd tags with the OllyDbg author (me). Version 2.xx makes it differently. For each plugin, OllyDbg automatically creates file-unique block of .udd record types. They are indexed by plugin names
(reported in ODBG2_Pluginquery(), not the name of DLL!). If there are two plugins with the same name, restored records may be sent to the wrong plugin. Therefore it is very important that plugin names are unique. A good (but of course insufficient) solution is to select random tags. For example, if both plugins use tags 1, 2 and 3, the collision is unavoidable. If tags are 121, 122 and 123 in one case and 9902, 9903 and 9904 in another, there will be no collision.

Each plugin may define 65535 plugin-unique tags in the range 1 .. 65535. Tag 0 is reserved for the future. For each data record plugin calls Pluginsaverecord() or Pluginpackedrecord(). If necessary, there may be several records with the same tag. Total size of the data that plugin may save to the .udd file is limited only by the disk capacity (although OllyDbg may experience some problems if file size exceeds 2 GB).

Global, process-oriented data must be saved to the main .udd file (named by .exe). Module-related data must be saved in module files. Don't forget to save all addresses relative to the module base, so that data will be restored correctly even if module is relocated.

Note that this function is called not only when module unloads, but also when user selects Save data to .udd file... in the Modules window.


void ODBG2_Pluginsaveudd(t_uddsave *psave,t_module *pmod,int ismainmodule);


Parameters:

psave
(in) Pointer to the structure of type t_uddsave. Plugins should treat this parameter as a handle and pass it unchanged to Pluginsaverecord() or Pluginpackedrecord()
pmod
(in) Pointer to the structure of type t_module that describes the processed module
ismainmodule
(in) 1 if this is the main module (usually belonging to the file with extention .exe) and 0 otherwise


Return values:

None


Example:

This simplified code is taken from the sample bookmark plugin:

#define BOOKMARKTAG    0x0001          // Tag of bookmark record

typedef struct t_uddmark {             // Bookmark in .udd file
  int            index;                // Bookmark index
  ulong          offset;               // Offset from module base
} t_uddmark;

extc void _export cdecl ODBG2_Pluginsaveudd(const t_uddsave *psave,
  t_module *pmod,int ismainmodule) {
  int i;
  t_bookmark *pmark;
  t_uddmark um;
  for (i=0; i<bookmark.sorted.n; i++) {
    pmark=(t_bookmark *)Getsortedbyindex(&(bookmark.sorted),i);
    if (pmark->addr>=pmod->base && pmark->addr<pmod->base+pmod->size) {
      um.index=pmark->index;
      um.offset=pmark->addr-pmod->base;
      Pluginsaverecord(psave,BOOKMARKTAG,sizeof(um),&um);
    }
  }
}

Plugin saves bookmarks that belong only to the specified module:

  if (pmark->addr>=pmod->base && pmark->addr<pmod->base+pmod->size) ...

 
Each record is a structure of type t_uddmark. Its size is fixed, but nothing prevents you from saving records of variable size. Note that record contains not the physical address of the bookmark, but its offset from the module base:

  um.offset=pmark->addr-pmod->base;


When restoring bookmarks, plugin will add module base to the offset. If module is loaded on a different base, bookmarks will get different physical addresses, but will point to the same commands - and this is what user expects.

But what will happen if bookmark is set outside of any module? In our case it will be lost. Let's hope that data pointed to by the bookmark will not be relocated. As there is no associated module, we are going to save orphan bookmarks in the main .udd file:

#define BOOKMARKTAG    0x0001          // Tag of bookmark record
#define ORPHANTAG      0x0002          // Tag of orphan bookmark record

typedef struct t_uddmark {             // Bookmark in .udd file
  int            index;                // Bookmark index
  ulong          addroffs;             // Address or offset from module base
} t_uddmark;

extc void _export cdecl ODBG2_Pluginsaveudd(const t_uddsave *psave,
  t_module *pmod,int ismainmodule) {
  int i,j;
  t_bookmark *pmark;
  t_uddmark um;
  t_module *pm;
  for (i=0; i<bookmark.sorted.n; i++) {

    pmark=(t_bookmark *)Getsortedbyindex(&(bookmark.sorted),i);
    if (pmark->addr>=pmod->base && pmark->addr<pmod->base+pmod->size) {
      um.index=pmark->index;
      um.addroffs=pmark->addr-pmod->base;
      Pluginsaverecord(psave,BOOKMARKTAG,sizeof(um),&um); }
    else if (ismainmodule) {
      for (j=0; j<module.sorted.n; j++) {
        pm=(t_module *)Getsortedbyindex(&(module.sorted),j);
        if (pm==NULL) continue;        // Must not happen!
        if (pmark->addr>=pm->base && pmark->addr<pm->base+pm->size)
          break;                       // Module found, not an orphan
        ;
      };
      if (j>=module.sorted.n) {
        um.index=pmark->index;
        um.addroffs=pmark->addr;       // This time direct address
        Pluginsaverecord(psave,ORPHANTAG,sizeof(um),&um);
      }
    }
  }

}

Here I walk the list of all available modules. If main module is processed and bookmark belongs to no defined module, it is saved with its absolute address and tag ORPHANTAG.


See also:
Plugins, t_module, ODBG2_Pluginuddrecord(), Pluginpackedrecord()Pluginsaverecord()