root/tools/finsig_vxworks.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. bprintf
  2. add_blankline
  3. write_output
  4. usage
  5. error
  6. match_compare
  7. addMatch
  8. fwAddMatch
  9. find_saved_sig
  10. save_sig
  11. get_saved_sig
  12. search_saved_sig
  13. match_apex2us
  14. find_apex2us
  15. find_mkdir
  16. find_pow
  17. find_log
  18. find_log10
  19. find_get_ptp_file_buf
  20. find_closedir
  21. find_add_ptp_handler
  22. find_PT_PlaySound
  23. find_ExportToEventProcedure
  24. find_RegisterEventProcedure
  25. find_set_control_event
  26. find_filesem_init
  27. find_getcurrentmachinetime
  28. find_get_nd_value
  29. find_get_current_nd_value_iris
  30. find_get_current_nd_value
  31. find_exmem_free
  32. find_exmem_alloc
  33. find_get_ptp_buf_size
  34. find_GetBaseSv
  35. find_func
  36. vxworks_offset
  37. fw_string_process
  38. fw_string_process_unaligned
  39. fw_process
  40. match_strsig1
  41. match_strsig2a
  42. match_strsig2
  43. match_strsig3a
  44. match_strsig3
  45. match_strsig4a
  46. match_strsig4
  47. match_strsig5a
  48. match_strsig5
  49. match_strsig6
  50. match_strsig7a
  51. match_strsig7
  52. match_strsig8
  53. find_strsig8
  54. find_strsig9
  55. match_strsig11
  56. match_strsig13a
  57. match_strsig13
  58. match_strsig15a
  59. match_strsig15
  60. match_strsig16
  61. find_strsig17
  62. find_strsig19
  63. match_strsig100
  64. match_strsig101
  65. match_strsig102
  66. match_strsig103
  67. match_strsig104
  68. find_strsig
  69. find_str_sig_matches
  70. find_matches
  71. print_results
  72. mode_name
  73. output_modemap
  74. find_modelist
  75. match_FlashParamsTable2
  76. match_FlashParamsTable
  77. find_modemap
  78. find_FileAccessSem
  79. find_DebugAssert_argcount
  80. find_platform_vals
  81. find_viewport_address
  82. match_vid_get_bitmap_fb
  83. match_get_flash_params_count
  84. match_uiprop_count
  85. isMOVLRPC
  86. match_imager_active
  87. find_lib_vals
  88. print_stubs_min
  89. print_exmem_types
  90. find_exmem_alloc_table
  91. match_levent_table
  92. match_movie_status
  93. match_full_screen_refresh
  94. match_canon_shoot_menu_active
  95. match_playrec_mode
  96. match_some_flag_for_af_scan
  97. match_palette_data
  98. match_palette_buffer_offset
  99. match_palette_data3
  100. match_palette_data2
  101. match_SavePaletteData
  102. match_viewport_address3
  103. match_viewport_address2
  104. match_viewport_address
  105. match_physw_status
  106. match_physw_run
  107. match_canon_menu_active
  108. match_zoom_busy
  109. match_focus_busy
  110. match_bitmap_buffer2
  111. match_bitmap_buffer
  112. match_raw_buffer
  113. find_DoMovieFrameCapture_buf
  114. find_stubs_min
  115. find_ctypes
  116. match_nrflag3
  117. match_nrflag
  118. match_nrflag2
  119. isADD_0x220000
  120. find_leds
  121. find_other_vals
  122. print_kval
  123. add_kinfo
  124. add_kmval
  125. kinfo_compare
  126. print_kmvals
  127. match_GetSDProtect
  128. find_key_vals
  129. get_eventproc_val
  130. add_func_name
  131. add_func_name2
  132. match_eventproc
  133. match_registerlists
  134. match_registerlistproc
  135. find_eventprocs
  136. isLDR_PC_r0
  137. isLDR_PC_r3
  138. match_createtask
  139. find_tasks
  140. find_builddate
  141. save_ptp_handler_func
  142. find_ptp_handler_imm
  143. match_ptp_handlers
  144. find_ptp_handlers
  145. write_levent_table_dump
  146. output_firmware_vals
  147. compare_func_names
  148. compare_func_addresses
  149. write_funcs
  150. main

   1 #include <stdlib.h>
   2 #include <stdio.h>
   3 #include <stdint.h>
   4 #include <string.h>
   5 #include <time.h>
   6 #include <stdarg.h>
   7 #include <ctype.h>
   8 
   9 #include "stubs_load.h"
  10 #include "firmware_load.h"
  11 #include "ptp_op_names.h"
  12 
  13 //------------------------------------------------------------------------------------------------------------
  14 // #define DEBUG_PRINT_ALL_FUNC_NAMES 1 // enable debug output on stderr for development
  15 // #define LIST_IMPORTANT_FUNCTIONS   1 // always list functions with 'LIST_ALWAYS' flag, even when not found
  16 // #define PRINT_LEVENT_TABLE 1         // print all levents to file
  17 //------------------------------------------------------------------------------------------------------------
  18 
  19 // Buffer output into header and body sections
  20 
  21 FILE    *out_fp;
  22 char    out_buf[32*1024] = "";
  23 int     out_len = 0;
  24 char    hdr_buf[32*1024] = "";
  25 int     hdr_len = 0;
  26 int     out_hdr = 1;
  27 
  28 void bprintf(char *fmt, ...)
  29 {
  30     va_list argp;
  31     va_start(argp, fmt);
  32 
  33     if (out_hdr)
  34         hdr_len += vsprintf(hdr_buf+hdr_len,fmt,argp);
  35     else
  36         out_len += vsprintf(out_buf+out_len,fmt,argp);
  37 
  38     va_end(argp);
  39 }
  40 
  41 void add_blankline()
  42 {
  43     if (strcmp(hdr_buf+hdr_len-2,"\n\n") != 0)
  44     {
  45         hdr_buf[hdr_len++] = '\n';
  46         hdr_buf[hdr_len] = 0;
  47     }
  48 }
  49 
  50 void write_output()
  51 {
  52     add_blankline();
  53     if (out_fp)
  54     {
  55         fprintf(out_fp,"%s",hdr_buf);
  56         fprintf(out_fp,"%s",out_buf);
  57     }
  58 }
  59 
  60 //------------------------------------------------------------------------------------------------------------
  61 
  62 void usage(char *err)
  63 {
  64     bprintf("finsig <primary> <base> <outputfilename> [alt base] - Error = %s\n",err);
  65     write_output();
  66     fprintf(stderr,"finsig <primary> <base> <outputfilename> [alt base] - Error = %s\n",err);
  67     exit(1);
  68 }
  69 
  70 void error(char *fmt, int n)
  71 {
  72     bprintf(fmt, n);
  73     write_output();
  74     exit(1);
  75 }
  76 
  77 //------------------------------------------------------------------------------------------------------------
  78 
  79 // Signature match handling
  80 
  81 // Structure to store match info
  82 typedef struct {
  83     uint32_t ptr;
  84     uint32_t fail;
  85     uint32_t success;
  86     int sig;
  87 } Match;
  88 
  89 // qsort compare function the Match struture
  90 int match_compare(const Match *p1, const Match *p2)
  91 {
  92     /* NOTE: If a function has *more* matches, it will be prefered, even if it has a lower percent matches */
  93     if (p1->success > p2->success)
  94     {
  95         if ((p2->fail == 0) && (p1->fail > 0))
  96         {
  97             return 1;
  98         }
  99         else
 100         {
 101             return -1;
 102         }
 103     }
 104     else if (p1->success < p2->success)
 105     {
 106         if ((p1->fail == 0) && (p2->fail > 0))
 107         {
 108             return -1;
 109         }
 110         else
 111         {
 112             return 1;
 113         }
 114     }
 115     else
 116     {
 117         if (p1->fail < p2->fail)
 118         {
 119             return -1;
 120         }
 121         else if (p1->fail > p2->fail)
 122         {
 123             return 1;
 124         }
 125     }
 126 
 127     if (p1->sig < p2->sig)
 128     {
 129         return -1;
 130     }
 131     else if (p1->sig > p2->sig)
 132     {
 133         return 1;
 134     }
 135 
 136     /* scores are equal. prefer lower address */
 137 
 138     if (p1->ptr < p2->ptr)
 139     {
 140         return -1;
 141     }
 142     else if (p1->ptr > p2->ptr)
 143     {
 144         return 1;
 145     }
 146 
 147     return 0;
 148 }
 149 
 150 #define MAX_MATCHES (8192)
 151 
 152 Match matches[MAX_MATCHES];
 153 int count;
 154 
 155 // Add a new Match
 156 void addMatch(uint32_t fadr, int s, int f, int sig)
 157 {
 158     matches[count].ptr = fadr;
 159     matches[count].success = s;
 160     matches[count].fail = f;
 161     matches[count].sig = sig;
 162     count++;
 163 }
 164 
 165 // Add a Match, adjust address for stuff in the block copied to RAM
 166 void fwAddMatch(firmware *fw, uint32_t fadr, int s, int f, int sig)
 167 {
 168     if ((fadr >= fw->base_copied) && (fadr < (fw->base_copied + fw->size2*4)))
 169     {
 170         addMatch(fadr - fw->base_copied + fw->base2,s,f,sig);
 171     }
 172     else
 173     {
 174         addMatch(fadr,s,f,sig);
 175     }
 176 }
 177 
 178 //------------------------------------------------------------------------------------------------------------
 179 
 180 // Signature structures generated by gensig2.exe
 181 
 182 typedef struct {
 183     uint32_t offs;
 184     uint32_t value;
 185     uint32_t mask;
 186 } FuncSig;
 187 
 188 typedef struct {
 189     const char *name;
 190     FuncSig *sig;
 191     int ver;
 192 } FuncsList;
 193 
 194 //------------------------------------------------------------------------------------------------------------
 195 
 196 // Master list of functions / addresses to find
 197 
 198 #define DONT_EXPORT     1
 199 #define OPTIONAL        2
 200 #define UNUSED          4
 201 #define BAD_MATCH       8
 202 #define EV_MATCH        16
 203 #define LIST_ALWAYS     32
 204 
 205 typedef struct {
 206     char        *name;
 207     int         flags;
 208     uint32_t    val;
 209 } func_entry;
 210 
 211 int next_func_entry = 0;
 212 
 213 #define MAX_FUNC_ENTRY  5000
 214 
 215 func_entry  func_names[MAX_FUNC_ENTRY] =
 216 {
 217     // Do these first as they are needed to find others
 218     { "ExportToEventProcedure_FW", UNUSED|DONT_EXPORT },
 219     { "RegisterEventProcedure_FW", UNUSED|DONT_EXPORT },
 220     //{ "CreateJumptable", UNUSED|DONT_EXPORT },
 221     { "_uartr_req", UNUSED|DONT_EXPORT },
 222     { "StartRecModeMenu", UNUSED|DONT_EXPORT },
 223     { "LogCameraEvent", UNUSED|DONT_EXPORT },
 224     { "IsControlEventActive", UNUSED|DONT_EXPORT }, // helper, vx
 225     { "GetLogicalEventName", UNUSED|DONT_EXPORT }, // helper, vx, name made up
 226 
 227     { "AllocateMemory", UNUSED },
 228     { "AllocateUncacheableMemory" },
 229     { "Close" },
 230     { "CreateBinarySemaphore" },
 231     { "CreateCountingSemaphore", UNUSED|DONT_EXPORT },
 232     { "CreateTask" },
 233     { "DebugAssert", OPTIONAL },
 234     { "DeleteDirectory_Fut", UNUSED|DONT_EXPORT },
 235     { "DeleteFile_Fut" },
 236     { "DeleteSemaphore", UNUSED|DONT_EXPORT },
 237     { "DoAELock" },
 238     { "DoAFLock" },
 239     { "EnterToCompensationEVF" },
 240     { "ExecuteEventProcedure" },
 241     { "ExitFromCompensationEVF" },
 242     { "ExitTask" },
 243     { "ExpCtrlTool_StartContiAE", OPTIONAL },
 244     { "ExpCtrlTool_StopContiAE", UNUSED|DONT_EXPORT },
 245     { "Fclose_Fut" },
 246     { "Feof_Fut" },
 247     { "Fflush_Fut" },
 248     { "Fgets_Fut" },
 249     { "Fopen_Fut" },
 250     { "Fread_Fut" },
 251     { "FreeMemory", UNUSED },
 252     { "FreeUncacheableMemory" },
 253     { "Fseek_Fut" },
 254     { "Fwrite_Fut" },
 255     { "GetBatteryTemperature" },
 256     { "GetCCDTemperature" },
 257     { "GetCurrentAvValue" },
 258     { "GetCurrentShutterSpeed" },
 259     { "GetUsableMaxAv", OPTIONAL },
 260     { "GetUsableMinAv", OPTIONAL },
 261     { "GetDrive_ClusterSize" },
 262     { "GetDrive_FreeClusters" },
 263     { "GetDrive_TotalClusters" },
 264     { "GetFocusLensSubjectDistance" },
 265     { "GetFocusLensSubjectDistanceFromLens" },
 266     { "GetImageFolder", OPTIONAL },
 267     { "GetKbdState", UNUSED|DONT_EXPORT },
 268     { "GetMemInfo", UNUSED|DONT_EXPORT },
 269     { "GetOpticalTemperature" },
 270     { "GetParameterData" },
 271     { "GetPropertyCase" },
 272     { "GetSystemTime" },
 273     { "GetVRAMHPixelsSize", UNUSED|DONT_EXPORT },
 274     { "GetVRAMVPixelsSize", UNUSED|DONT_EXPORT },
 275     { "GetZoomLensCurrentPoint" },
 276     { "GetZoomLensCurrentPosition" },
 277     { "GiveSemaphore", OPTIONAL },
 278     { "IsStrobeChargeCompleted" },
 279     { "LEDDrive", OPTIONAL },
 280     { "LocalTime" },
 281     { "LockMainPower" },
 282     { "Lseek", UNUSED|DONT_EXPORT },
 283     { "MakeDirectory_Fut" },
 284     { "MakeSDCardBootable", OPTIONAL },
 285     { "MoveFocusLensToDistance" },
 286     { "MoveIrisWithAv", OPTIONAL },
 287     { "MoveZoomLensWithPoint" },
 288     { "NewTaskShell", UNUSED|DONT_EXPORT },
 289     { "Open" },
 290     { "PB2Rec", UNUSED|DONT_EXPORT },
 291     { "PT_MoveDigitalZoomToWide", OPTIONAL },
 292     { "PT_MoveOpticalZoomAt", OPTIONAL },
 293     { "PT_PlaySound" },
 294     { "PostLogicalEventForNotPowerType" },
 295     { "PostLogicalEventToUI" },
 296     { "PutInNdFilter", OPTIONAL },
 297     { "PutOutNdFilter", OPTIONAL },
 298     { "Read" },
 299 //    { "ReadFastDir", UNUSED|DONT_EXPORT },
 300     { "Rec2PB", UNUSED|DONT_EXPORT },
 301     { "RefreshPhysicalScreen" },
 302     { "Remove", OPTIONAL|UNUSED },
 303     { "RenameFile_Fut" },
 304     { "Restart" },
 305     { "ScreenLock", OPTIONAL },
 306     { "ScreenUnlock", OPTIONAL },
 307     { "SetAE_ShutterSpeed" },
 308     { "SetAutoShutdownTime" },
 309     { "SetCurrentCaptureModeType" },
 310     { "SetFileAttributes" },
 311     { "SetFileTimeStamp", UNUSED|DONT_EXPORT },
 312     { "SetLogicalEventActive" },
 313     { "SetParameterData" },
 314     { "SetPropertyCase" },
 315     { "SetScriptMode" },
 316     { "SleepTask" },
 317     { "TakeSemaphore" },
 318     { "TurnOffBackLight" },
 319     { "TurnOnBackLight" },
 320     { "TurnOnDisplay" },
 321     { "TurnOffDisplay" },
 322     { "UIFS_WriteFirmInfoToFile", UNUSED|DONT_EXPORT },
 323     { "UnlockAE" },
 324     { "UnlockAF" },
 325     { "UnlockMainPower" },
 326     { "UnsetZoomForMovie", OPTIONAL },
 327     { "UpdateMBROnFlash" },
 328     { "VbattGet" },
 329     { "Write" },
 330     { "WriteSDCard" },
 331 
 332     { "_log" },
 333     { "_log10" },
 334     { "_pow" },
 335     { "_sqrt" },
 336     { "add_ptp_handler" },
 337     { "apex2us" },
 338     { "close" },
 339     { "err_init_task", OPTIONAL },
 340     { "exmem_alloc" },
 341     { "exmem_free", OPTIONAL },
 342     { "exmem_ualloc", UNUSED|OPTIONAL|LIST_ALWAYS },
 343     { "exmem_ufree", UNUSED|OPTIONAL|LIST_ALWAYS },
 344     { "exmem_assert", UNUSED|OPTIONAL|LIST_ALWAYS }, // helper
 345     { "free" },
 346     { "get_nd_value", OPTIONAL },
 347     { "get_current_exp", UNUSED|OPTIONAL },
 348     { "get_current_nd_value", OPTIONAL },
 349     { "GetBaseSv", OPTIONAL|UNUSED },
 350 
 351     { "kbd_p1_f" },
 352     { "kbd_p1_f_cont" },
 353     { "kbd_p2_f" },
 354     { "kbd_read_keys", UNUSED|DONT_EXPORT },
 355     { "kbd_read_keys_r2" },
 356 
 357     { "kbd_pwr_off" },
 358     { "kbd_pwr_on" },
 359     { "lseek" },
 360     { "malloc" },
 361     { "memcmp" },
 362     { "memcpy" },
 363     { "memset" },
 364     { "mkdir" },
 365     { "mktime_ext", UNUSED|DONT_EXPORT },
 366     { "open" },
 367 //    { "OpenFastDir", UNUSED|DONT_EXPORT },
 368     { "closedir" },
 369     { "qsort" },
 370     { "rand" },
 371     { "read", UNUSED|DONT_EXPORT },
 372     { "realloc", OPTIONAL },
 373     { "reboot_fw_update", UNUSED|DONT_EXPORT },
 374     { "set_control_event", UNUSED|DONT_EXPORT },
 375     { "srand" },
 376     { "stat" },
 377     { "strcat" },
 378     { "strchr" },
 379     { "strcmp" },
 380     { "strcpy" },
 381     { "strftime" },
 382     { "strlen" },
 383     { "strncmp" },
 384     { "strncpy" },
 385     { "strrchr" },
 386     { "strtol" },
 387 //    { "strtolx", UNUSED|DONT_EXPORT },
 388 
 389     { "isdigit" },
 390     { "isspace" },
 391     { "isalpha" },
 392     { "isupper" },
 393     { "islower" },
 394     { "ispunct" },
 395     { "isxdigit" },
 396     { "toupper" },
 397     { "tolower" },
 398     { "taskLock" },
 399     { "taskUnlock" },
 400     { "taskName" },
 401     { "taskIdListGet" },
 402     { "errnoOfTaskGet" },
 403     { "readdir" },
 404     { "strtoul" },
 405     { "strpbrk" },
 406     { "utime" },
 407     { "localtime" },
 408     { "mktime" },
 409     { "opendir" },
 410     { "memchr" },
 411     { "memPartInfoGet" },
 412     { "iosDrvInstall" },
 413     { "iosDevAdd" },
 414     { "iosDevDelete" },
 415     { "GetCurrentTargetDistance" },
 416     { "taskCreateHookAdd" },
 417     { "taskDeleteHookAdd" },
 418     { "Mount_FileSystem" },
 419     { "Unmount_FileSystem" },
 420     { "MakeAFScan" },
 421     { "taskSuspend" },
 422     { "taskResume" },
 423 
 424     { "task_CaptSeq", UNUSED|DONT_EXPORT },
 425     { "task_ExpDrv", UNUSED|DONT_EXPORT },
 426     { "task_FileWrite", UNUSED|DONT_EXPORT },
 427     { "task_InitFileModules", UNUSED|DONT_EXPORT },
 428     { "task_MovieRecord", UNUSED|DONT_EXPORT },
 429     { "task_PhySw", UNUSED|DONT_EXPORT },
 430     { "task_SwitchCheck", UNUSED|DONT_EXPORT }, // old name for task_PhySw
 431     { "task_RotaryEncoder", UNUSED|DONT_EXPORT },
 432 //    { "task_TouchPanel", OPTIONAL },
 433 
 434     //{ "hook_CreateTask" },
 435 
 436     { "time" },
 437     { "vsprintf" },
 438     { "write", UNUSED|DONT_EXPORT },
 439 
 440     { "EngDrvIn", OPTIONAL|UNUSED },
 441     { "EngDrvOut", OPTIONAL|UNUSED },
 442     { "EngDrvRead" },
 443     { "EngDrvBits", OPTIONAL|UNUSED },
 444 
 445     { "PTM_GetCurrentItem" },
 446     { "PTM_SetCurrentItem", UNUSED },
 447     { "PTM_NextItem", OPTIONAL|UNUSED },
 448     { "PTM_PrevItem", OPTIONAL|UNUSED },
 449     { "PTM_SetPropertyEnable", OPTIONAL|UNUSED },
 450 
 451     // OS functions, mostly to aid firmware analysis. Order is important!
 452     { "PT_GetSystemTime", OPTIONAL|UNUSED }, // only for locating timer functions
 453     { "_GetSystemTime", OPTIONAL|UNUSED }, // only for locating timer functions
 454     { "SetTimerAfter", OPTIONAL|UNUSED },
 455     { "SetTimerWhen", OPTIONAL|UNUSED },
 456     { "CancelTimer", OPTIONAL|UNUSED },
 457     { "CancelHPTimer" },
 458     { "SetHPTimerAfterTimeout", OPTIONAL|UNUSED },
 459     { "SetHPTimerAfterNow" },
 460     { "CreateTaskStrictly", OPTIONAL|UNUSED },
 461     { "CreateMessageQueue", OPTIONAL|UNUSED },
 462     { "CreateRecursiveLock", OPTIONAL|UNUSED },
 463     { "GetSemaphoreValue", OPTIONAL|UNUSED },
 464     { "TryTakeSemaphore", OPTIONAL|UNUSED },
 465     { "CreateMessageQueueStrictly", OPTIONAL|UNUSED },
 466     { "CreateEventFlagStrictly", OPTIONAL|UNUSED },
 467     { "CreateBinarySemaphoreStrictly", OPTIONAL|UNUSED },
 468     { "CreateCountingSemaphoreStrictly", OPTIONAL|UNUSED },
 469     { "CreateRecursiveLockStrictly", OPTIONAL|UNUSED },
 470     { "DeleteMessageQueue", OPTIONAL|UNUSED },
 471     { "PostMessageQueue", OPTIONAL|UNUSED },
 472     { "ReceiveMessageQueue", OPTIONAL|UNUSED },
 473     { "TryReceiveMessageQueue", OPTIONAL|UNUSED },
 474     { "TryPostMessageQueue", OPTIONAL|UNUSED },
 475     { "GetNumberOfPostedMessages", OPTIONAL|UNUSED },
 476     { "DeleteRecursiveLock", OPTIONAL|UNUSED },
 477     { "AcquireRecursiveLock", OPTIONAL|UNUSED },
 478     { "ReleaseRecursiveLock", OPTIONAL|UNUSED },
 479     { "WaitForAnyEventFlag", OPTIONAL|UNUSED },
 480     { "WaitForAllEventFlag", OPTIONAL|UNUSED },
 481     { "ClearEventFlag", OPTIONAL|UNUSED },
 482     { "SetEventFlag", OPTIONAL|UNUSED },
 483     { "GetEventFlagValue", OPTIONAL|UNUSED },
 484     { "CreateEventFlag", OPTIONAL|UNUSED },
 485     { "DeleteEventFlag", OPTIONAL|UNUSED },
 486     { "CheckAnyEventFlag", OPTIONAL|UNUSED },
 487     { "CheckAllEventFlag", OPTIONAL|UNUSED },
 488     { "RegisterInterruptHandler", OPTIONAL|UNUSED },
 489     { "UnregisterInterruptHandler", OPTIONAL|UNUSED },
 490     { "GetSRAndDisableInterrupt", OPTIONAL|UNUSED }, // disables IRQ, returns a value
 491     { "SetSR", OPTIONAL|UNUSED }, // enables IRQ, puts back value returned by GetSR
 492     { "EnableInterrupt", OPTIONAL|UNUSED }, // enables IRQ
 493     { "GetCurrentMachineTime", OPTIONAL|UNUSED }, // reads usec counter, name from ixus30
 494     { "HwOcReadICAPCounter", OPTIONAL|UNUSED }, // reads usec counter, name from ixus30
 495 
 496     // Other stuff needed for finding misc variables - don't export to stubs_entry.S
 497     { "GetSDProtect", UNUSED|DONT_EXPORT },
 498     { "DispCon_ShowBitmapColorBar", UNUSED },
 499     { "ResetZoomLens", OPTIONAL|UNUSED },
 500     { "ResetFocusLens", OPTIONAL|UNUSED },
 501     { "NR_GetDarkSubType", OPTIONAL|UNUSED },
 502     { "NR_SetDarkSubType", OPTIONAL|UNUSED },
 503     { "SavePaletteData", OPTIONAL|UNUSED },
 504     { "GUISrv_StartGUISystem", OPTIONAL|UNUSED },
 505     { "get_resource_pointer", OPTIONAL|UNUSED }, // name made up, gets a pointer to a certain resource (font, dialog, icon)
 506 
 507     { "wrapped_malloc", UNUSED|DONT_EXPORT},    // helper to find malloc, finds the other allocator on ixus30/40
 508     { "malloc_alt", UNUSED|DONT_EXPORT },       // should be the same as malloc when found
 509     { "WaitForEventFlag", UNUSED|DONT_EXPORT }, // helper to find other eventflag functions
 510 
 511     { "filesem_init", OPTIONAL|UNUSED }, // file semaphore init function, needed for verification
 512     { "ImagerActivate", OPTIONAL|UNUSED }, // helper
 513     { "DoMovieFrameCapture", OPTIONAL|UNUSED },
 514     { "MenuIn", OPTIONAL|UNUSED },
 515     { "MenuOut", OPTIONAL|UNUSED },
 516 
 517     { "MFOn", OPTIONAL },
 518     { "MFOff", OPTIONAL },
 519 
 520     { "GetAdChValue", OPTIONAL },
 521     { "get_ptp_buf_size", OPTIONAL },
 522     { "get_ptp_file_buf", OPTIONAL },
 523 
 524     { 0, 0, 0 }
 525 };
 526 
 527 // Return the array index of a named function in the array above
 528 int find_saved_sig(const char *name)
 529 {
 530     int i;
 531     for (i=0; func_names[i].name != 0; i++)
 532     {
 533         if (strcmp(name,func_names[i].name) == 0)
 534         {
 535             return i;
 536         }
 537     }
 538     return -1;
 539 }
 540 
 541 // Save the address value found for a function in the above array
 542 void save_sig(const char *name, uint32_t val)
 543 {
 544     int i = find_saved_sig(name);
 545     if (i >= 0)
 546     {
 547         func_names[i].val = val;
 548     }
 549 }
 550 
 551 // Get the saved address value for a named function
 552 // If the address value is 0 then assume the function search has not occurred yet, so go search for it.
 553 int get_saved_sig(firmware *fw, const char *name)
 554 {
 555     int i = find_saved_sig(name);
 556     if (i >= 0)
 557     {
 558         if (func_names[i].val == 0)
 559         {
 560             // See if the function is in the 'func_list' array below
 561             int find_func(const char* name);
 562             int k1 = find_func(name);
 563             if (k1 >= 0)
 564             {
 565                 // if found do full search
 566                 void find_matches(firmware*,const char*);
 567                 find_matches(fw, name);
 568                 count = 0;
 569             }
 570             else
 571             {
 572                 // not found, only do string matching search
 573                 void find_str_sig_matches(firmware*,const char*);
 574                 find_str_sig_matches(fw, name);
 575                 count = 0;
 576             }
 577         }
 578         if (func_names[i].val == 0)
 579         {
 580             // If not found return invalid index
 581             i = -1;
 582         }
 583     }
 584     return i;
 585 }
 586 
 587 // Search for something relative to the location stored for a previously matched function
 588 // Matching is done via the 'func' function, searching continues until 'func' returns non-zero
 589 // Starts searching at 'ofst' from the saved address for a max of 'len' instructions
 590 // Returns the 'func' value or 0 if no match found
 591 int search_saved_sig(firmware *fw, char *sig, int (*func)(firmware*, int, int), int v, int ofst, int len)
 592 {
 593     int k = get_saved_sig(fw, sig);
 594     if (k >= 0)
 595     {
 596         int idx = adr2idx(fw, func_names[k].val);
 597         for (k=idx+ofst; k<idx+ofst+len; k++)
 598         {
 599             int rv = func(fw, k, v);
 600             if (rv)
 601                 return rv;
 602         }
 603     }
 604     return 0;
 605 }
 606 
 607 //------------------------------------------------------------------------------------------------------------
 608 
 609 // New string / signature matching structure
 610 
 611 // Structure for matching
 612 
 613 typedef struct {
 614     int     type;               // 1 = func*, string, 2 = string, ... string*, func*, 3 = ADR Rx, func, ADR Ry, string, BL, ... string, etc
 615     char    *name;              // function name
 616     char    *ev_name;           // event / other name to match in the firmware
 617     int     offset;             // offset for following branches, or other tests
 618     // VxWorks version specific offsets?
 619     int     vxworks_offset;
 620 } string_sig;
 621 
 622 // Load old signature matching data generated by gensig_vxworks
 623 #include "signatures_vxworks.h"
 624 
 625 //------------------------------------------------------------------------------------------------------------
 626 
 627 // Data for matching 'apex2us' function
 628 uint32_t apex2us_test[] = { 0x3D09000, 0x3BBA304, 0x3A728D2, 0x3931EF4, 0x37F8303, 0x36C52A2, 0x3598B85, 0x3472B6A, 0 };
 629 
 630 // Special case for apex2us
 631 int match_apex2us(firmware *fw, int k, uint32_t v1, uint32_t v2)
 632 {
 633     if (isLDR_PC(fw,k) && (LDR2val(fw,k) == v1) && ((fwRd(fw,k) == 1) || (fwRd(fw,k) == 2)))
 634     {
 635         k = find_inst_rev(fw, isSTMFD_LR, k, 200);
 636         if (k != 0)
 637         {
 638             if (fwval(fw,k-2) == 0xE3700D09)    // CMN R0, #0x240
 639                 k -= 2;
 640             uint32_t fadr = idx2adr(fw,k);
 641             fwAddMatch(fw,fadr,32,0,121);
 642             return 1;
 643         }
 644     }
 645     return 0;
 646 }
 647 int find_apex2us(firmware *fw, string_sig *sig, int j)
 648 {
 649     int i;
 650     for (i=0; apex2us_test[i] != 0; i++)
 651         if (fwval(fw,j+i) != apex2us_test[i])
 652             return 0;
 653 
 654     return search_fw(fw, match_apex2us, idx2adr(fw,j), 0, 1);
 655 }
 656 
 657 // Special case for mkdir
 658 int find_mkdir(firmware *fw, string_sig *sig, int k)
 659 {
 660     if (fwval(fw,k) == 0x12CEA600)
 661     {
 662         k = find_inst_rev(fw, isSTMFD_LR, k-20, 200);
 663         if (k != 0)
 664         {
 665             if ((((fwval(fw,k+12) & 0xFFF0FFFF) == 0xE350002F) && ((fwval(fw,k+15) & 0xFFF0FFFF) == 0xE3500021) && ((fwval(fw,k+19) & 0xFFF0FFFF) == 0xE3500020)) ||
 666                 (((fwval(fw,k+11) & 0xFFF0FFFF) == 0xE350002F) && ((fwval(fw,k+14) & 0xFFF0FFFF) == 0xE3500021) && ((fwval(fw,k+18) & 0xFFF0FFFF) == 0xE3500020)))
 667             {
 668                 uint32_t fadr = 0;
 669                 if (isBL(fw,k+47))
 670                 {
 671                     fadr = followBranch(fw, idx2adr(fw,k+47), 0x01000001);
 672                 }
 673                 else if (isBL(fw,k+48))
 674                 {
 675                     fadr = followBranch(fw, idx2adr(fw,k+48), 0x01000001);
 676                 }
 677                 if (fadr != 0)
 678                 {
 679                     fwAddMatch(fw,fadr,32,0,121);
 680                     return 1;
 681                 }
 682             }
 683         }
 684     }
 685     return 0;
 686 }
 687 
 688 // Special case for _pow
 689 int find_pow(firmware *fw, string_sig *sig, int j)
 690 {
 691     if (!idx_valid(fw,j) || !idx_valid(fw,j+3)) return 0;
 692     // Find values passed to _pow
 693     if ((fwval(fw,j) == 0x00000000) && (fwval(fw,j+1) == 0x40000000) && (fwval(fw,j+2) == 0x00000000) && (fwval(fw,j+3) == 0x408F4000))
 694     {
 695         uint32_t adr1 = idx2adr(fw,j);      // address of 1st value
 696         uint32_t adr2 = idx2adr(fw,j+2);    // address of 2nd value
 697         int j1;
 698 
 699         for (j1 = j-5; j1>0; j1--)
 700         {
 701             if (isADR_PC_cond(fw,j1) &&                 // ADR ?
 702                 (fwval(fw,j1+1) == 0xE8900003) &&       // LDMIA R0,{R0,R1}
 703                 isBL(fw,j1+2) &&                        // BL
 704                 isADR_PC_cond(fw,j1+4))                 // ADR ?
 705             {
 706                 if ((ADR2adr(fw,j1) == adr1) && (ADR2adr(fw,j1+4) == adr2))
 707                 {
 708                     uint32_t fadr = followBranch(fw,idx2adr(fw,j1+2),0x01000001);
 709                     fwAddMatch(fw,fadr,32,0,121);
 710                     return 1;
 711                 }
 712             }
 713             else
 714             if (isADR_PC_cond(fw,j1) &&                 // ADR ?
 715                 (fwval(fw,j1+1) == 0xE8900003) &&       // LDMIA R0,{R0,R1}
 716                 isBL(fw,j1+2) &&                        // BL
 717                 isADR_PC_cond(fw,j1+3))                 // ADR ?
 718             {
 719                 if ((ADR2adr(fw,j1) == adr1) && (ADR2adr(fw,j1+3) == adr2))
 720                 {
 721                     uint32_t fadr = followBranch(fw,idx2adr(fw,j1+2),0x01000001);
 722                     fwAddMatch(fw,fadr,32,0,121);
 723                     return 1;
 724                 }
 725             }
 726             else
 727             if (isADR_PC_cond(fw,j1) &&                 // ADR ?
 728                 (fwval(fw,j1+2) == 0xE8900003) &&       // LDMIA R0,{R0,R1}
 729                 isBL(fw,j1+3) &&                        // BL
 730                 isADR_PC_cond(fw,j1+4))                 // ADR ?
 731             {
 732                 if ((ADR2adr(fw,j1) == adr1) && (ADR2adr(fw,j1+4) == adr2))
 733                 {
 734                     uint32_t fadr = followBranch(fw,idx2adr(fw,j1+3),0x01000001);
 735                     fwAddMatch(fw,fadr,32,0,121);
 736                     return 1;
 737                 }
 738             }
 739         }
 740     }
 741 
 742     return 0;
 743 }
 744 
 745 // Special case for _log & _log10
 746 int find_log(firmware *fw, string_sig *sig, int j)
 747 {
 748     // Find values passed to _log
 749     if (isBL(fw,j) && isLDR_PC(fw,j+1) && (LDR2val(fw,j+1) == 0x3FDBCB7B) && isLDR_PC(fw,j+2) && (LDR2val(fw,j+2) == 0x1526E50E))
 750     {
 751         uint32_t fadr = followBranch(fw,idx2adr(fw,j),0x01000001);
 752         fwAddMatch(fw,fadr,32,0,121);
 753         return 1;
 754     }
 755 
 756     return 0;
 757 }
 758 int find_log10(firmware *fw, string_sig *sig, int j)
 759 {
 760     // Find values passed to _log
 761     if (isBL(fw,j) && isLDR_PC(fw,j+1) && (LDR2val(fw,j+1) == 0x3FDBCB7B) && isLDR_PC(fw,j+2) && (LDR2val(fw,j+2) == 0x1526E50E))
 762     {
 763         int k = find_inst_rev(fw, isSTMFD_LR, j-1, 100);
 764         uint32_t fadr = idx2adr(fw,k);
 765         fwAddMatch(fw,fadr,32,0,121);
 766         return 1;
 767     }
 768 
 769     return 0;
 770 }
 771 // Special case for get_ptp_file_buf
 772 int find_get_ptp_file_buf(firmware *fw, string_sig *sig, int j)
 773 {
 774     /*
 775      * looking for
 776      * MOV r0,#4
 777      * BNE 
 778      * BL get_ptp_buf_size
 779      * BIC r1, r0, #1
 780      * MOV r0,#4
 781      * BL sub...
 782     */
 783     if(!(isMOV_immed(fw,j) 
 784         && (fwRn(fw,j) == 0)
 785         && ((fwval(fw,j+1) & 0xFF000000) == 0x1A000000) // BNE
 786         && isBL(fw,j+2) 
 787         && ((fwval(fw,j+3) & 0xFFF00000) == 0xe3C00000) // BIC
 788         && (ALUop2(fw,j+3) == 1)
 789         && isMOV_immed(fw,j+4)
 790         && (fwRn(fw,j+4) == 0)
 791         && isBL(fw,j+5))) {
 792         return 0;
 793     }
 794     if(ALUop2(fw,j) != 4 || ALUop2(fw,j+4) != 4) {
 795         return 0;
 796     }
 797 
 798     uint32_t f1 = followBranch(fw,idx2adr(fw,j+2),0x01000001);
 799     int i = get_saved_sig(fw,"get_ptp_buf_size");
 800     // if sig not found, end search completely
 801     if(i < 0) {
 802         // fprintf(stderr,"find_get_ptp_file_buf func missing @0x%08x\n",idx2adr(fw,j));
 803         return 1;
 804     }
 805     if(f1 != func_names[i].val) {
 806         // fprintf(stderr,"find_get_ptp_file_buf func mismatch @0x%08x\n",idx2adr(fw,j));
 807         return 0;
 808     }
 809     // search backwards for push
 810     int k = find_inst_rev(fw, isSTMFD_LR, j-1, 8);
 811     if(k < 0) {
 812         // fprintf(stderr,"find_get_ptp_file_buf failed to find push @0x%08x\n",idx2adr(fw,j));
 813         return 0;
 814     }
 815     // functions could have a MOV, LDR etc before the push, but not seen for this function
 816     uint32_t fadr = idx2adr(fw, k);
 817     fwAddMatch(fw,fadr,32,0,121);
 818     // fprintf(stderr,"find_get_ptp_file_buf match @0x%08x\n",fadr);
 819 
 820     return 1;
 821 }
 822 
 823 // Special case for 'closedir' (DryOS)
 824 int find_closedir(firmware *fw)
 825 {
 826     int j = get_saved_sig(fw,"OpenFastDir");
 827     if (j >= 0)
 828     {
 829         int k = find_inst(fw, isSTMFD_LR, adr2idx(fw,func_names[j].val)+1, 100);
 830         if (isB(fw,k-1) && isBL(fw,k-2))
 831         {
 832             uint32_t fadr = followBranch(fw, idx2adr(fw, k-2), 0x01000001);
 833             fwAddMatch(fw,fadr,32,0,121);
 834             return 1;
 835         }
 836     }
 837 
 838     return 0;
 839 }
 840 
 841 // Special case for 'add_ptp_handler'
 842 int find_add_ptp_handler(firmware *fw, string_sig *sig, int k)
 843 {
 844     uint32_t vals[] = { 0x9801, 0x9802, 0x9803, 0x9804, 0x9805, 0 };
 845     uint32_t fadr = 0;
 846 
 847     int i = 0;
 848     while ((vals[i] != 0) && isLDR_PC(fw,k) && (fwRd(fw,k) == 0) && (LDR2val(fw,k) == vals[i]))
 849     {
 850         k = find_inst(fw, isBL, k+1, 5);
 851         if (k == 0) return 0;
 852         if (fadr == 0)
 853             fadr = followBranch(fw, idx2adr(fw,k), 0x01000001);
 854         k = find_inst(fw, isLDR_PC, k+1, 5);
 855         if (k == 0) return 0;
 856         i++;
 857     }
 858 
 859     if (fadr != 0)
 860     {
 861         fwAddMatch(fw,fadr,32,0,121);
 862         return 1;
 863     }
 864 
 865     return 0;
 866 }
 867 
 868 // Special case for 'PT_PlaySound'
 869 int find_PT_PlaySound(firmware *fw)
 870 {
 871     int j, k;
 872     int k1 = get_saved_sig(fw,"LogCameraEvent");
 873 
 874     if (k1 >= 0)
 875     {
 876         j = find_str_ref(fw,"BufAccBeep");
 877         if (j >= 0)
 878         {
 879             k = find_inst(fw, isBL, j+1, 4);
 880             if (k >= 0)
 881             {
 882                 uint32_t fadr = followBranch(fw, idx2adr(fw,k), 0x01000001);
 883                 if (func_names[k1].val == fadr)
 884                 {
 885                     k = find_inst(fw, isB, k+1, 10);
 886                     fadr = followBranch(fw, idx2adr(fw, k), 1);
 887                     fwAddMatch(fw,fadr,32,0,122);
 888                     return 1;
 889                 }
 890             }
 891         }
 892     }
 893 
 894     return 0;
 895 }
 896 
 897 // Special case for 'ExportToEventProcedure'
 898 int find_ExportToEventProcedure(firmware *fw)
 899 {
 900     int k = find_str_ref(fw,"ExportToEventProcedure");
 901 
 902     if (k >= 0)
 903     {
 904         if (isLDR_PC(fw,k+1) && (isBorBL(fw,k+2) || isBorBL(fw,k+3)) && (fwRd(fw,k+1) == 1))
 905         {
 906             uint32_t fadr = LDR2val(fw,k+1);
 907             fwAddMatch(fw,fadr,32,0,122);
 908             return 1;
 909         }
 910     }
 911 
 912     return 0;
 913 }
 914 
 915 // Special case for 'RegisterEventProcedure'
 916 int find_RegisterEventProcedure(firmware *fw)
 917 {
 918     int k = find_str_ref(fw,"CreateProxyOfEventProcedure");
 919 
 920     if (k >= 0)
 921     {
 922         if (isLDR_PC(fw,k+1) && (isBorBL(fw,k+2) || isBorBL(fw,k+3)) && (fwRd(fw,k) == 0))
 923         {
 924             uint32_t fadr = 0;
 925             if (isBorBL(fw,k+2))
 926                 fadr = followBranch(fw,idx2adr(fw,k+2),0x01000001);
 927             else
 928                 fadr = followBranch(fw,idx2adr(fw,k+3),0x01000001);
 929             fwAddMatch(fw,fadr,32,0,122);
 930             return 1;
 931         }
 932     }
 933 
 934     return 0;
 935 }
 936 
 937 // Special case for set_control_event (Vx)
 938 int find_set_control_event(firmware *fw)
 939 {
 940     int j1, j2, k, found, n;
 941     int k1 = get_saved_sig(fw,"IsControlEventActive");
 942     int k2 = get_saved_sig(fw,"GetLogicalEventName");
 943 
 944     if ((k1 >= 0) && (k2 >= 0))
 945     {
 946         j1 = adr2idx(fw, func_names[k1].val);
 947         j2 = adr2idx(fw, func_names[k2].val);
 948         found = 0;
 949         // search from IsControlEventActive backwards
 950         for (k=j1-1; k>j1-256; k--)
 951         {
 952             if (isBL(fw,k))
 953             {
 954                 if (j2 == idxFollowBranch(fw,k,0x01000001))
 955                 {
 956                     // reference to GetLogicalEventName found
 957                     found = 1;
 958                     break;
 959                 }
 960             }
 961         }
 962         if (found)
 963         {
 964             found = 0;
 965             // locate function start
 966             k = find_inst_rev(fw,isSTMFD_LR,k,60);
 967             // locate function end
 968             j2 = find_inst(fw,isLDMFD_PC,k+1,128);
 969             if ( (k<0) || (j2<0) )
 970                 return 0;
 971             int prevbldest = 0;
 972             n = 0;
 973             k++;
 974             // look for not more than 7 BLs
 975             while (n<7)
 976             {
 977                 k = find_inst(fw,isBL,k,32);
 978                 // too late hit or no hit
 979                 if ( (k>j2) || (k<0) )
 980                     return 0;
 981                 j1 = idxFollowBranch(fw,k,0x01000001);
 982                 if (prevbldest==j1)
 983                 {
 984                     // two consecutive calls to set_control_event
 985                     found = 1;
 986                     break;
 987                 }
 988                 prevbldest = j1;
 989                 n++;
 990                 k++;
 991             }
 992             if (found)
 993             {
 994                 fwAddMatch(fw,idx2adr(fw,j1),32,0,122);
 995                 return 1;
 996             }
 997         }
 998     }
 999     return 0;
1000 }
1001 
1002 // see also find_FileAccessSem()
1003 int find_filesem_init(firmware *fw)
1004 {
1005     int s1 = find_str(fw, "FileSem.c");
1006     if (s1 < 0)
1007         return 0;
1008     s1 = find_inst(fw, isLDR_PC, s1+2, 16);
1009     if (s1 < 0)
1010         return 0;
1011     s1 = find_inst_rev(fw, isSTMFD_LR, s1-1, 16);
1012     if (s1 < 0)
1013         return 0;
1014     fwAddMatch(fw,idx2adr(fw,s1),32,0,122);
1015     return 1;
1016 }
1017 
1018 int find_getcurrentmachinetime(firmware *fw)
1019 {
1020     int f1 = get_saved_sig(fw,"SetHPTimerAfterNow");
1021     if (f1 < 0)
1022         return 0;
1023     f1 = adr2idx(fw, func_names[f1].val);
1024     f1 = find_inst(fw, isBL, f1, 16);
1025     if (f1>0)
1026     {
1027         f1 = idxFollowBranch(fw,f1,0x01000001);
1028         fwAddMatch(fw,idx2adr(fw,f1),32,0,122);
1029         return 1;
1030     }
1031     return 0;
1032 }
1033 
1034 // for cams with ND and Iris (g7)
1035 int find_get_nd_value(firmware *fw)
1036 {
1037     // match is only for cams with both, task is mostly a good indicator
1038     if((get_saved_sig(fw,"task_NdActuator") < 0) || (get_saved_sig(fw,"task_IrisEvent") < 0)) {
1039         return 0;
1040     }
1041     int f1 = find_saved_sig("get_nd_value");
1042     if ((f1 >= 0) && (func_names[f1].val != 0)) // return if func already found
1043         return 0;
1044 
1045     f1 = get_saved_sig(fw,"PutInNdFilter_FW");
1046     int f2 = get_saved_sig(fw,"ClearEventFlag");
1047 
1048     if ((f1 < 0) || (f2 < 0))
1049         return 0;
1050 
1051     f1 = adr2idx(fw, func_names[f1].val);
1052     f2 = adr2idx(fw, func_names[f2].val);
1053     int k1 = find_Nth_inst(fw,isBL,f1,10,2);
1054     int k2 = find_inst(fw,isBL,f1,6);
1055     if ((k1 == -1) || (k2 == -1))
1056         return 0;
1057     if ( followBranch2(fw,idx2adr(fw,k2),0x01000001) != idx2adr(fw,f2) ) // ClearEventFlag?
1058         return 0;
1059     
1060     // note the folliwng isn't super robust, but only one model
1061     k1 = idxFollowBranch(fw,k1,0x01000001); // PutInNdFilter_low veneer
1062     k1 = find_inst(fw,isB,k1,3); // veneer
1063     if (k1 == -1) {
1064         return 0;
1065     }
1066     k1 = idxFollowBranch(fw,k1,0x00000001); // PutInNdFilter_low
1067     if (k1 == -1) {
1068         return 0;
1069     }
1070     k1 = find_inst(fw,isBL,k1,4); // get_nd_value wrapper
1071     if (k1 == -1) {
1072         return 0;
1073     }
1074     k1 = idxFollowBranch(fw,k1,0x01000001); // 
1075     k1 = find_inst(fw,isBL,k1,2); // get_nd_value
1076     if (k1 == -1) {
1077         return 0;
1078     }
1079     k1 = idxFollowBranch(fw,k1,0x01000001);
1080     fwAddMatch(fw,idx2adr(fw,k1),32,0,122);
1081     return 1;
1082 }
1083 
1084 // for cams with both ND and iris
1085 int find_get_current_nd_value_iris(firmware *fw)
1086 {
1087     // match is only for cams with both, task is mostly a good indicator
1088     if((get_saved_sig(fw,"task_NdActuator") < 0) || (get_saved_sig(fw,"task_IrisEvent") < 0)) {
1089         return 0;
1090     }
1091     int f1 = get_saved_sig(fw,"get_current_exp");
1092     if(f1 < 0)
1093         return 0;
1094 
1095     f1 = adr2idx(fw, func_names[f1].val);
1096     int blcnt, i;
1097     // expect
1098     // 2x bl DebugAssert
1099     // followed by 5 bl with other instruction between
1100     // looking for 5th
1101     for(i=0, blcnt=0; i<28 && blcnt < 8; i++) {
1102         if(!isBL(fw,f1+i)) {
1103             continue;
1104         }
1105         blcnt++;
1106         if(blcnt == 7) {
1107             int f2 = idxFollowBranch(fw,f1+i,0x01000001);
1108             // non-ND cameras have a call to return 0
1109             if(isMOV(fw,f2) && (fwRd(fw,f2) == 0) && (fwOp2(fw,f2) == 0)) // MOV R0, 0
1110                 return 0;
1111             // expect wrapper that pushes LR, makes return a short
1112             if(isBL(fw,f2+1)) {
1113                 f2 = idxFollowBranch(fw,f2+1,0x01000001);
1114                 fwAddMatch(fw,idx2adr(fw,f2),32,0,122);
1115                 return 1;
1116             }
1117             return 0;
1118         }
1119     }
1120     return 0;
1121 }
1122 
1123 int find_get_current_nd_value(firmware *fw)
1124 {
1125 
1126     // string only present on ND-only cameres
1127     if(find_str(fw, "IrisSpecification.c") < 0) {
1128         return find_get_current_nd_value_iris(fw);
1129     }
1130 
1131     int f1 = get_saved_sig(fw,"GetCurrentAvValue");
1132     if(f1 < 0)
1133         return 0;
1134 
1135     f1 = adr2idx(fw, func_names[f1].val);
1136     // skip wrapper
1137     if (!isBL(fw,f1+1))
1138         return 0;
1139     f1 = idxFollowBranch(fw,f1+1,0x01000001);
1140     // expect
1141     // ldr r0, ="IrisController.c"
1142     // bl DebugAssert
1143     // bl get_current_nd_value
1144     int sadr = find_str(fw, "IrisController.c");
1145     int j = find_nxt_str_ref(fw, sadr, f1);
1146     if ((j < 0) || (j-f1 > 8))
1147         return 0;
1148 
1149     j = find_Nth_inst(fw,isBL,j,8,2);
1150     if (j == -1)
1151         return 0;
1152     f1 = idxFollowBranch(fw,j,0x01000001);
1153     fwAddMatch(fw,idx2adr(fw,f1),32,0,122);
1154     return 1;
1155 }
1156 
1157 int find_exmem_free(firmware *fw)
1158 {
1159 
1160     int k = get_saved_sig(fw,"ExMem.FreeCacheable_FW"); // newer cam, a wrapped version of exmem_free is already located
1161     if (k >= 0)
1162         return 0;
1163     k = get_saved_sig(fw,"memset_FW");
1164     if (k < 0)
1165         return 0;
1166     k = adr2idx(fw, func_names[k].val);
1167     int sadr = find_str(fw, "ComMemMan.c"); // always there
1168     int j = find_nxt_str_ref(fw, sadr, sadr);
1169     if (j < 0)
1170         return 0;
1171     j = find_nxt_str_ref(fw, sadr, j+1);
1172     if (j < 0)
1173         return 0;
1174     int n;
1175     for (n=j+8; n<j+36; n++)
1176     {
1177         if (isBL(fw,n))
1178         {
1179             if (idx2adr(fw,idxFollowBranch(fw,n,0x01000001)) == idx2adr(fw,k))
1180             {
1181                 int m = find_inst_rev(fw,isBL,n-1,4);
1182                 if (m != -1)
1183                 {
1184                     m = idxFollowBranch(fw,m,0x01000001);
1185                     fwAddMatch(fw,idx2adr(fw,m),32,0,122);
1186                     return 1;
1187                 }
1188             }
1189         }
1190     }
1191     return 0;
1192 }
1193 
1194 int find_exmem_alloc(firmware *fw)
1195 {
1196 
1197     int k = get_saved_sig(fw,"ExMem.AllocCacheable_FW"); // newer cam, a wrapped version of exmem_alloc is already located
1198     if (k >= 0)
1199         return 0;
1200     k = get_saved_sig(fw,"DebugAssert"); // 
1201     if (k < 0)
1202         return 0;
1203     k = adr2idx(fw, func_names[k].val);
1204     int sadr = find_str(fw, "ComMemMan.c"); // always there
1205     int j = find_nxt_str_ref(fw, sadr, sadr);
1206     if (j < 0)
1207         return 0;
1208     int m = find_inst(fw,isBorBL,j+3,10);
1209     if (m != -1)
1210     {
1211         m = idxFollowBranch(fw,m,0x01000001);
1212         if (idx2adr(fw,m) != idx2adr(fw,k))
1213         {
1214             fwAddMatch(fw,idx2adr(fw,m),32,0,122);
1215             return 1;
1216         }
1217     }
1218     return 0;
1219 }
1220 
1221 int find_get_ptp_buf_size(firmware *fw)
1222 {
1223     int j = get_saved_sig(fw,"handle_PTP_OC_SendObject"); // same handler as CANON_SendObjectByPath
1224     if(j < 0) {
1225         // fprintf(stderr,"find_get_ptp_buf_size missing handle_PTP_OC_SendObject\n");
1226         return 0;
1227     }
1228     int k=adr2idx(fw,func_names[j].val);
1229     int k_max=k+120;
1230     uint32_t adr=0;
1231     // ID of the file buffer appears to always be 4 on vxworks
1232     // very early cams have a hard coded size
1233     int file_buf_id=4;
1234 
1235     for(; k < k_max;k++) {
1236         // look for
1237         // mov r0,#file_buf_id
1238         // bl ...
1239         if(isMOV_immed(fw,k) && fwRn(fw,k) == 0 && ALUop2(fw,k) == file_buf_id && isBL(fw, k+1)) {
1240             adr = followBranch(fw,idx2adr(fw,k+1),0x01000001);
1241             // fprintf(stderr,"find_get_ptp_buf_size match 1 0x%08x @0x%08x\n",adr,idx2adr(fw,k+1));
1242             break;
1243         }
1244     }
1245     if(!adr) {
1246         // fprintf(stderr,"find_get_ptp_buf_size no match\n");
1247         return 0;
1248     }
1249     // look for same seq again, within 6 ins
1250     k_max = k+6;
1251     for(; k < k_max;k++) {
1252         if(isMOV_immed(fw,k) && fwRn(fw,k) == 0 && ALUop2(fw,k) == file_buf_id && isBL(fw, k+1)) {
1253             uint32_t adr2 = followBranch(fw,idx2adr(fw,k+1),0x01000001);
1254             // is it the same address?
1255             if(adr2 == adr) {
1256                 // fprintf(stderr,"find_get_ptp_buf_size match 2 @0x%08x\n",idx2adr(fw,k+1));
1257                 fwAddMatch(fw,adr,32,0,122);
1258                 return 0;
1259             }
1260             // fprintf(stderr,"find_get_ptp_buf_size match 2 mismatch 0x%08x != 0x%08x @0x%08x\n",adr,adr2,idx2adr(fw,k+1));
1261         }
1262     }
1263     return 0;
1264 }
1265 
1266 int find_GetBaseSv(firmware *fw)
1267 {
1268     int j = get_saved_sig(fw,"SetPropertyCase");
1269     if (j < 0)
1270         return 0;
1271     j = adr2idx(fw, func_names[j].val);
1272     int j2 = get_saved_sig(fw,"DebugAssert");
1273     if (j2 < 0)
1274         return 0;
1275     j2 = adr2idx(fw, func_names[j2].val);
1276     
1277     int sadr = find_str(fw, "Sensitive.c");
1278     if (sadr < fw->lowest_idx)
1279         return 0;
1280     int s1 = find_nxt_str_ref(fw, sadr, -1/*fw->lowest_idx*/);
1281     int hist[3] = {0, 0, 0};
1282     while (s1 >= 0)
1283     {
1284         hist[2] = hist[1];
1285         hist[1] = hist[0];
1286         hist[0] = s1;
1287         if (hist[0] && hist[1] && hist[2])
1288         {
1289             if ((hist[0]-hist[1]<7) && (hist[1]-hist[2]<9))
1290             {
1291                 int n;
1292                 for (n=s1+1; n<s1+26; n++)
1293                 {
1294                     if ( isBL(fw, n) )
1295                     {
1296                         int k;
1297                         k = idxFollowBranch(fw,n,0x01000001);
1298                         if ( idx2adr(fw, k) == idx2adr(fw, j) )
1299                         {
1300                             // SetPropertyCase call found
1301                             k = find_inst(fw, isBL, s1+2, 6);
1302                             if (k != -1)
1303                             {
1304                                 int l = idxFollowBranch(fw,k,0x01000001);
1305                                 if (idx2adr(fw,l) == idx2adr(fw,j2)) // DebugAssert?
1306                                 {
1307                                     k = find_inst(fw, isBL, k+1, 6);
1308                                     if (k == -1)
1309                                         break;
1310                                     l = idxFollowBranch(fw,k,0x01000001);
1311                                 }
1312                                 if ( (fwval(fw,l)==0xe52de004) &&
1313                                      (fwval(fw,l+4)==0xe49df004) &&
1314                                      isBL(fw,l+1) )
1315                                 {
1316                                     void add_func_name(char*, uint32_t, char*);
1317                                     add_func_name("j_GetBaseSv", idx2adr(fw,l), "");
1318                                     k = idxFollowBranch(fw,l+1,0x01000001);
1319                                     fwAddMatch(fw,idx2adr(fw,k),32,0,122);
1320                                     return 1;
1321                                 }
1322                             }
1323                         }
1324                     }
1325                 }
1326             }
1327         }
1328         s1 = find_nxt_str_ref(fw, sadr, s1+1);
1329     }
1330 
1331     return 0;
1332 }
1333 
1334 
1335 //------------------------------------------------------------------------------------------------------------
1336 
1337 // Data for matching the '_log' function
1338 uint32_t log_test[] = {
1339     0x1526E50E, 0x3FDBCB7B, 0
1340 };
1341 
1342 // Data for matching 'Fut' functions
1343 uint32_t DeleteDirectory_Fut_test[] = { 0x09400017 };
1344 uint32_t MakeDirectory_Fut_test[]   = { 0x09400015 };
1345 uint32_t RenameFile_Fut_test[]      = { 0x09400013 };
1346 
1347 //------------------------------------------------------------------------------------------------------------
1348 
1349 // Signature matching data
1350 string_sig string_sigs[] =
1351 {
1352     // Same as previously found eventproc - do these first
1353     {20, "AllocateMemory", "AllocateMemory_FW", 1 },
1354     {20, "Close", "Close_FW", 1 },
1355     {20, "CreateCountingSemaphore", "CreateCountingSemaphore_FW", 1 },
1356     {20, "CreateTask", "CreateTask_FW", 1 },
1357     {20, "DeleteSemaphore", "DeleteSemaphore_FW", 1 },
1358     {20, "DispCon_ShowBitmapColorBar", "DispCon_ShowBitmapColorBar_FW", 1 },
1359     {20, "ExitTask", "ExitTask_FW", 1 },
1360     {20, "Fclose_Fut", "Fclose_Fut_FW", 1 },
1361     {20, "Fopen_Fut", "Fopen_Fut_FW", 1 },
1362     {20, "Fread_Fut", "Fread_Fut_FW", 1 },
1363     {20, "FreeMemory", "FreeMemory_FW", 1 },
1364     {20, "Fseek_Fut", "Fseek_Fut_FW", 1 },
1365     {20, "Fwrite_Fut", "Fwrite_Fut_FW", 1 },
1366     {20, "GetSDProtect", "GetSDProtect_FW", 1 },
1367     //{20, "GetSystemTime", "GetSystemTime_FW", 1 },
1368     {20, "GetCurrentAvValue", "GetCurrentAvValue_FW", 1 },
1369     {20, "GetCurrentShutterSpeed", "GetCurrentShutterSpeed_FW", 1 },
1370     {20, "GetUsableMaxAv", "GetUsableMaxAv_FW", 1 },
1371     {20, "GetUsableMinAv", "GetUsableMinAv_FW", 1 },
1372     {20, "GetOpticalTemperature", "GetOpticalTemperature_FW", 1 },
1373     {20, "GetVRAMHPixelsSize", "GetVRAMHPixelsSize_FW", 1 },
1374     {20, "GetVRAMVPixelsSize", "GetVRAMVPixelsSize_FW", 1 },
1375     {20, "GetZoomLensCurrentPoint", "GetZoomLensCurrentPoint_FW", 1 },
1376     {20, "GiveSemaphore", "GiveSemaphore_FW", 1 },
1377     {20, "GUISrv_StartGUISystem", "GUISrv_StartGUISystem_FW", 1 },
1378     {20, "LEDDrive", "LEDDrive_FW", 1 },
1379     {20, "LockMainPower", "LockMainPower_FW", 1 },
1380     //{20, "lseek", "Lseek_FW", 1 },
1381     {20, "Lseek", "Lseek_FW", 1 },
1382     {20, "MoveIrisWithAv", "MoveIrisWithAv_FW", 1 },
1383     {20, "MoveZoomLensWithPoint", "MoveZoomLensWithPoint_FW", 1 },
1384     {20, "memcmp", "memcmp_FW", 1 },
1385     {20, "memcpy", "memcpy_FW", 1 },
1386     {20, "memset", "memset_FW", 1 },
1387     {20, "NewTaskShell", "NewTaskShell_FW", 1 },
1388     {20, "NR_GetDarkSubType", "NR_GetDarkSubType_FW", 1 },
1389     {20, "NR_SetDarkSubType", "NR_SetDarkSubType_FW", 1 },
1390     {20, "Open", "Open_FW", 1 },
1391     {20, "PostLogicalEventForNotPowerType", "PostLogicalEventForNotPowerType_FW", 1 },
1392     {20, "PostLogicalEventToUI", "PostLogicalEventToUI_FW", 1 },
1393     {20, "PT_MoveDigitalZoomToWide", "PT_MoveDigitalZoomToWide_FW", 1 },
1394     {20, "PT_MoveOpticalZoomAt", "PT_MoveOpticalZoomAt_FW", 1 },
1395     {20, "Read", "Read_FW", 1 },
1396     {20, "RefreshPhysicalScreen", "RefreshPhysicalScreen_FW", 1 },
1397     {20, "ResetFocusLens", "ResetFocusLens_FW", 1 },
1398     {20, "ResetZoomLens", "ResetZoomLens_FW", 1 },
1399     {20, "SavePaletteData", "SavePaletteData_FW", 1 },
1400     {20, "SetAutoShutdownTime", "SetAutoShutdownTime_FW", 1 },
1401     {20, "SetCurrentCaptureModeType", "SetCurrentCaptureModeType_FW", 1 },
1402     {20, "SetScriptMode", "SetScriptMode_FW", 1 },
1403     {20, "SleepTask", "SleepTask_FW", 1 },
1404     {20, "strcmp", "j_strcmp_FW", 0 },
1405     {20, "strcmp", "strcmp_FW", 0 },
1406     {20, "strcpy", "strcpy_FW", 1 },
1407     {20, "strlen", "strlen_FW", 1 },
1408     {20, "StartRecModeMenu", "StartRecModeMenu_FW", 1 },
1409     //{20, "TakeSemaphore", "TakeSemaphore_FW", 1 },
1410     {20, "UIFS_WriteFirmInfoToFile", "UIFS_WriteFirmInfoToFile_FW", 1 },
1411     {20, "UnlockMainPower", "UnlockMainPower_FW", 1 },
1412     {20, "VbattGet", "VbattGet_FW", 1 },
1413     {20, "write", "Write_FW", 1 },
1414     {20, "Write", "Write_FW", 1 },
1415     {20, "task_CaptSeq", "task_CaptSeqTask", 1 },
1416     {20, "task_ExpDrv", "task_ExpDrvTask", 1 },
1417     {20, "task_FileWrite", "task_FileWriteTask", 1 },
1418     {20, "task_RotaryEncoder", "task_JogDial", 1 },
1419     {20, "task_RotaryEncoder", "task_RotarySw", 1 },
1420     {20, "task_SwitchCheck", "task_SwitchCheckTask", 1 },
1421     {20, "IsControlEventActive", "IsControlEventActive_FW", 0 },
1422     {20, "GetLogicalEventName", "ShowLogicalEventName_FW", 0x01000002 },
1423     {20, "TurnOnDisplay", "DispCon_TurnOnDisplay_FW", 0 },
1424     {20, "TurnOffDisplay", "DispCon_TurnOffDisplay_FW", 0 },
1425     {20, "UnlockAF", "PT_UnlockAF_FW", 0x01000002 }, // newer Vx
1426     {20, "DoAFLock", "PT_DoAFLock_FW", 0x01000002 }, // newer Vx
1427     {20, "DoAFLock", "DoAFLock_FW", 1 },
1428     {20, "UnlockAF", "UnlockAF_FW", 1 },
1429     {20, "UnlockAE", "PT_UnlockAE_FW", 0x01000002 }, // newer Vx
1430     {20, "DoAELock", "PT_DoAELock_FW", 0x01000002 }, // newer Vx
1431     {20, "DoAELock", "DoAELock_FW", 1 },
1432     {20, "UnlockAE", "UnlockAE_FW", 1 },
1433     {20, "MFOn", "MFOn_FW", 1 },
1434     {20, "MFOff", "MFOff_FW", 1 },
1435     {20, "GetAdChValue", "GetAdChValue_FW", 0 },
1436     {20, "HwOcReadICAPCounter", "GetCurrentMachineTime", 3 },
1437     {20, "get_nd_value", "NdActuator.GetNdFilterDeltaEvAdjustValue_FW", 0 }, // old vx
1438     {20, "get_current_nd_value", "NdActuator.GetNdFilterDeltaEv_FW", 0 }, // old vx
1439     {20, "MenuIn", "MenuIn_FW", 1 },
1440     {20, "MenuOut", "MenuOut_FW", 1 },
1441 
1442     { 1, "ExportToEventProcedure_FW", "ExportToEventProcedure", 1 },
1443     { 1, "AllocateMemory", "AllocateMemory", 1 },
1444     { 1, "Close", "Close", 1 },
1445     { 1, "CreateTask", "CreateTask", 1 },
1446     { 1, "DoAFLock", "PT_DoAFLock", 0x01000002 },
1447     { 1, "ExitTask", "ExitTask", 1 },
1448     { 1, "exmem_alloc", "ExMem.AllocCacheable", 5 },
1449     { 1, "exmem_free", "ExMem.FreeCacheable", 0x01000003 },
1450     { 1, "exmem_ualloc", "ExMem.AllocUncacheable", 5 },
1451     { 1, "exmem_ufree", "ExMem.FreeUncacheable", 0x01000003 },
1452     { 1, "Fclose_Fut", "Fclose_Fut", 1 },
1453     { 1, "Feof_Fut", "Feof_Fut", 1 },
1454     { 1, "Fflush_Fut", "Fflush_Fut", 1 },
1455     { 1, "Fgets_Fut", "Fgets_Fut", 1 },
1456     { 1, "Fopen_Fut", "Fopen_Fut", 1 },
1457     { 1, "Fread_Fut", "Fread_Fut", 1 },
1458     { 1, "FreeMemory", "FreeMemory", 1 },
1459     { 1, "Fseek_Fut", "Fseek_Fut", 1 },
1460     { 1, "Fwrite_Fut", "Fwrite_Fut", 1 },
1461     { 1, "GetParameterData", "PTM_RestoreUIProperty", 0xF0000004 },
1462     { 1, "GetPropertyCase", "PT_GetPropertyCaseString", 1 },
1463     { 1, "GetPropertyCase", "PT_GetPropertyCaseInt", 0x0100000F },
1464     { 1, "GetPropertyCase", "GetPropertyCase", 0x0100000F },
1465     { 1, "GetSDProtect", "GetSDProtect", 1 },
1466     { 1, "GetSystemTime", "GetSystemTime", 1 },
1467     { 1, "LEDDrive", "LEDDrive", 1 },
1468     { 1, "LockMainPower", "LockMainPower", 1 },
1469     { 1, "Lseek", "Lseek", 1 },
1470     { 1, "lseek", "Lseek", 1 },
1471     { 1, "memcpy", "memcpy", 1 },
1472     { 1, "memcmp", "memcmp", 1 },
1473     { 1, "memset", "memset", 1 },
1474     { 1, "NewTaskShell", "NewTaskShell", 1 },
1475     { 1, "Open", "Open", 1 },
1476     { 1, "PostLogicalEventToUI", "PostLogicalEventToUI", 1 },
1477     { 1, "PostLogicalEventForNotPowerType", "PostLogicalEventForNotPowerType", 1 },
1478     { 1, "Read", "Read", 1 },
1479     { 1, "read", "Read", 1 },
1480     { 1, "RefreshPhysicalScreen", "RefreshPhysicalScreen", 1 },
1481     { 1, "SetAutoShutdownTime", "SetAutoShutdownTime", 1 },
1482     { 1, "SetCurrentCaptureModeType", "SetCurrentCaptureModeType", 1 },
1483     { 1, "SetLogicalEventActive", "UiEvnt_SetLogicalEventActive", 1 },
1484     { 1, "SetParameterData", "PTM_BackupUIProperty", 1 },
1485     { 1, "SetPropertyCase", "PT_SetPropertyCaseInt", 0x01000003 },
1486     { 1, "SetPropertyCase", "SetPropertyCase", 0x01000004 },
1487     { 1, "SetScriptMode", "SetScriptMode", 1 },
1488     { 1, "SleepTask", "SleepTask", 1 },
1489     { 1, "strcmp", "strcmp", 0 },
1490     { 1, "strcpy", "strcpy", 1 },
1491     { 1, "strlen", "strlen", 1 },
1492     { 1, "strtol", "atol", 3 },
1493     { 1, "TakeSemaphore", "TakeSemaphore", 1 },
1494     { 1, "UIFS_WriteFirmInfoToFile", "UIFS_WriteFirmInfoToFile", 1 },
1495     //{ 1, "UnlockAF", "PT_UnlockAF", 0x01000002 },
1496     { 1, "UnlockMainPower", "UnlockMainPower", 1 },
1497     { 1, "VbattGet", "VbattGet", 1 },
1498     { 1, "Write", "Write", 1 },
1499     { 1, "write", "Write", 1 },
1500     { 1, "GUISrv_StartGUISystem", "GUISrv_StartGUISystem", 1 },
1501 
1502     { 2, "GetBatteryTemperature", "GetBatteryTemperature", 1 },
1503     { 2, "GetCCDTemperature", "GetCCDTemperature", 1 },
1504     { 2, "GetOpticalTemperature", "GetOpticalTemperature", 1 },
1505     //{ 2, "GetFocusLensSubjectDistance", "GetCurrentTargetDistance", 1 },
1506     { 2, "GetZoomLensCurrentPoint", "GetZoomLensCurrentPoint", 1 },
1507     { 2, "GetZoomLensCurrentPosition", "GetZoomLensCurrentPosition", 1 },
1508     { 2, "MoveFocusLensToDistance", "MoveFocusLensToDistance", 1 },
1509     { 2, "MoveZoomLensWithPoint", "MoveZoomLensWithPoint", 1 },
1510     //{ 2, "GetCurrentAvValue", "GetCurrentAvValue", 1 },
1511     { 2, "PT_MoveOpticalZoomAt", "PT_MoveOpticalZoomAt", 1 },
1512     //{ 2, "PT_MoveOpticalZoomAt", "SS.MoveOpticalZoomAt", 1 },
1513     { 2, "PT_MoveDigitalZoomToWide", "PT_MoveDigitalZoomToWide", 1 },
1514     //{ 2, "PT_MoveDigitalZoomToWide", "SS.MoveDigitalZoomToWide", 1 },
1515     { 2, "MoveIrisWithAv", "MoveIrisWithAv", 1},
1516     //{ 2, "PutInNdFilter", "TurnOnNdFilter", 1 },
1517     //{ 2, "PutOutNdFilter", "TurnOffNdFilter", 1 },
1518     //{ 2, "PutInNdFilter", "PutInNdFilter", 1 },
1519     //{ 2, "PutOutNdFilter", "PutOutNdFilter", 1 },
1520     //{ 2, "IsStrobeChargeCompleted", "EF.IsChargeFull", 1 },
1521     { 2, "GetPropertyCase", "PT_GetPropertyCaseInt", 0x01000012 },
1522     { 2, "SetPropertyCase", "PT_SetPropertyCaseInt", 0x01000008 },
1523     { 2, "SetPropertyCase", "PT_SetPropertyCaseInt", 0x01000009 },
1524     //{ 2, "UnlockAF", "PT_UnlockAF", 0x01000002 },
1525     //{ 2, "UnlockAF", "SS.UnlockAF", 0x01000002 },
1526     //{ 2, "DoAFLock", "PT_DoAFLock", 0x01000002 },
1527     //{ 2, "DoAFLock", "SS.DoAFLock", 0x01000002 },
1528     { 2, "GetSystemTime", "PT_GetSystemTime", 0x01000003 },
1529     { 2, "PT_PlaySound", "PT_PlaySound", 0x01000005 },
1530     { 2, "StartRecModeMenu", "StartRecModeMenu", 1 },
1531     { 2, "GetSDProtect", "GetSDProtect", 1 },
1532     { 2, "DispCon_ShowBitmapColorBar", "DispCon_ShowBitmapColorBar", 1 },
1533     { 2, "SetAE_ShutterSpeed", "SetAE_ShutterSpeed", 1 },
1534     { 2, "ResetZoomLens", "ResetZoomLens", 1 },
1535     { 2, "ResetFocusLens", "ResetFocusLens", 1 },
1536     { 2, "NR_GetDarkSubType", "NR_GetDarkSubType", 1 },
1537     //{ 2, "NR_GetDarkSubType", "NRTBL.GetDarkSubType", 1 },
1538     { 2, "NR_SetDarkSubType", "NR_SetDarkSubType", 1 },
1539     //{ 2, "NR_SetDarkSubType", "NRTBL.SetDarkSubType", 1 },
1540     { 2, "SavePaletteData", "SavePaletteData", 1 },
1541     { 2, "GetVRAMHPixelsSize", "GetVRAMHPixelsSize", 1 },
1542     { 2, "GetVRAMVPixelsSize", "GetVRAMVPixelsSize", 1 },
1543     { 2, "EngDrvIn", "EngDrvIn", 4 },
1544     { 2, "EngDrvOut", "EngDrvOut", 0x01000005 },
1545     { 2, "EngDrvRead", "EngDrvRead", 4 },
1546     { 2, "EngDrvBits", "EngDrvBits", 0x01000006 },
1547     { 2, "exmem_alloc", "ExMem.AllocCacheable", 6 },
1548     { 2, "exmem_free", "ExMem.FreeCacheable", 0x01000003 },
1549     { 2, "exmem_ualloc", "ExMem.AllocUncacheable", 6 },
1550     { 2, "exmem_ufree", "ExMem.FreeUncacheable", 0x01000003 },
1551 
1552     { 2, "PTM_GetCurrentItem", "PTM_GetCurrentItem", 0x01000003 },
1553     { 2, "PTM_SetCurrentItem", "PTM_SetCurrentItem", 8 },
1554     { 2, "PTM_NextItem", "PTM_NextItem", 0x01000003 },
1555     { 2, "PTM_PrevItem", "PTM_PrevItem", 0x01000003 },
1556     { 2, "PTM_SetPropertyEnable", "PTM_SetProprietyEnable", 8 },
1557 
1558     { 3, "AllocateMemory", "AllocateMemory", 1 },
1559     { 3, "FreeMemory", "FreeMemory", 1 },
1560     { 3, "PostLogicalEventToUI", "PostLogicalEventToUI", 1 },
1561     { 3, "PostLogicalEventForNotPowerType", "PostLogicalEventForNotPowerType", 1 },
1562     { 3, "LockMainPower", "LockMainPower", 1 },
1563     { 3, "UnlockMainPower", "UnlockMainPower", 1 },
1564     { 3, "SetAutoShutdownTime", "SetAutoShutdownTime", 1 },
1565     { 3, "NewTaskShell", "NewTaskShell", 1 },
1566     { 3, "VbattGet", "VbattGet", 1 },
1567     { 3, "LEDDrive", "LEDDrive", 1 },
1568     { 3, "SetPropertyCase", "PT_SetPropertyCaseInt", 0x01000003 },
1569     //{ 3, "UnlockAF", "PT_UnlockAF", 0x01000002 },
1570     //{ 3, "DoAFLock", "PT_DoAFLock", 0x01000002 },
1571     { 3, "UIFS_WriteFirmInfoToFile", "UIFS_WriteFirmInfoToFile", 1 },
1572     { 3, "PT_MoveOpticalZoomAt", "PT_MoveOpticalZoomAt", 1 },
1573     { 3, "PT_MoveDigitalZoomToWide", "PT_MoveDigitalZoomToWide", 1 },
1574     { 3, "PT_PlaySound", "PT_PlaySound", 1 },
1575     { 3, "exmem_alloc", "ExMem.AllocCacheable", 4 },
1576     { 3, "exmem_free", "ExMem.FreeCacheable", 0x01000003 },
1577     { 3, "GetSDProtect", "GetSDProtect", 1 },
1578 
1579     { 4, "TurnOnBackLight", "TurnOnBackLight", 1 },
1580     { 4, "TurnOffBackLight", "TurnOffBackLight", 1 },
1581     { 4, "EnterToCompensationEVF", "SSAPI::EnterToCompensationEVF", 1 },
1582     { 4, "EnterToCompensationEVF", "ExpComp On", 1 },
1583     { 4, "EnterToCompensationEVF", "ExpOn", 1 },
1584     { 4, "ExitFromCompensationEVF", "SSAPI::ExitFromCompensationEVF", 1 },
1585     { 4, "ExitFromCompensationEVF", "ExpComp Off", 1 },
1586     { 4, "ExitFromCompensationEVF", "ExpOff", 1 },
1587     //{ 4, "PB2Rec", "AC:PB2Rec", 1 },
1588     //{ 4, "PB2Rec", "AC:PB2Rec", 6 },
1589     //{ 4, "PB2Rec", "AC:PB2Rec", 11 },
1590     //{ 4, "Rec2PB", "AC:Rec2PB", 1 },
1591     { 4, "RefreshPhysicalScreen", "ScreenUnLock", 1 },
1592     { 4, "RefreshPhysicalScreen", "ScreenUnLock", 7 },
1593     { 4, "RefreshPhysicalScreen", "ScreenUnLock", 15 },
1594     { 4, "RefreshPhysicalScreen", "Reduce ScreenUnLock", 5 },
1595     { 4, "RefreshPhysicalScreen", "Window:IneffectiveLockPhysicalScreen", 8 },
1596     { 4, "UnsetZoomForMovie", "ZoomCon_UnsetZoomForMovie", 1 },
1597     { 4, "ExpCtrlTool_StopContiAE", "StopContiAE", 9 },
1598     { 4, "ExpCtrlTool_StopContiAE", "StopContiAE", 10 },
1599     { 4, "ExpCtrlTool_StartContiAE", "StartContiAE", 9 },
1600     { 4, "ExpCtrlTool_StartContiAE", "StartContiAE", 10 },
1601     { 4, "ExecuteEventProcedure", "Can not Execute ", 14 },
1602 
1603     { 5, "UIFS_WriteFirmInfoToFile", "UIFS_WriteFirmInfoToFile", 1 },
1604     { 5, "CreateTask", "CreateTask", 1 },
1605     //{ 5, "hook_CreateTask", "CreateTask", 1 },
1606     { 5, "ExitTask", "ExitTask", 1 },
1607     { 5, "SleepTask", "SleepTask", 1 },
1608     { 5, "DeleteSemaphore", "DeleteSemaphore", 1 },
1609     { 5, "CreateCountingSemaphore", "CreateCountingSemaphore", 1 },
1610     //                                                                   ???
1611     { 5, "UpdateMBROnFlash", "MakeBootDisk", 0x01000003,                  11 },
1612     { 5, "MakeSDCardBootable", "MakeBootDisk", 0x01000003,                 1 },
1613 
1614     //{ 6, "Restart", "Bye", 0 },
1615     { 6, "GetImageFolder", "GetCameraObjectTmpPath ERROR[ID:%lx] [TRY:%lx]\n", 0 },
1616     { 6, "reboot_fw_update", "FirmUpgrade.c", 0 },
1617 
1618     { 7, "CreateTaskStrictly", "FileWriteTask", 0x01000001 },
1619     { 7, "RegisterInterruptHandler", "SdDmaInt", 0x01000001 },
1620     { 7, "LogCameraEvent", "BufAccBeep", 0x01000001 },
1621     { 7, "LogCameraEvent", "MyCamFunc_PlaySound_MYCAM_COVER_OPEN", 0x01000001 },
1622     { 7, "exmem_assert", "Type < MAX_NUM_OF_EXMEMORY_TYPE", 0x01000001 },
1623 
1624     { 8, "WriteSDCard", "Mounter.c", 0 },
1625 
1626     // Ensure ordering in func_names is correct for dependencies here
1627     //                                                                   ???
1628     //{ 9, "kbd_p1_f", "task_PhySw", 0,                                      5 },
1629     //{ 9, "kbd_p2_f", "task_PhySw", 0,                                      7 },
1630     { 9, "kbd_read_keys", "kbd_p1_f", 0,                                   2 },
1631     { 9, "kbd_p1_f_cont", "kbd_p1_f", -1,                                  3 },
1632     //{ 9, "kbd_read_keys_r2", "kbd_read_keys", 0,                          11 },
1633     { 9, "GetKbdState", "kbd_read_keys", 0,                                8 },
1634     { 9, "GetKbdState", "kbd_read_keys", 0,                                9 },
1635     //{ 9, "strtolx", "strtol", 0,                                           1 },
1636     //{ 9, "mkdir", "MakeDirectory_Fut", 0x01000001,                        17 },
1637     //{ 9, "mkdir", "MakeDirectory_Fut", 0x01000002,                        17 },
1638     //{ 9, "time", "MakeDirectory_Fut", 0,                                  12 },
1639     { 9, "stat", "_uartr_req", 0,                                          0 },
1640     //{ 9, "PostMessageQueue", "PostMessageQueueStrictly", 0,                3 },
1641     //{ 9, "WaitForAnyEventFlag", "WaitForAnyEventFlagStrictly", 0,          3 },
1642     //{ 9, "WaitForAllEventFlag", "WaitForAllEventFlagStrictly", 0,          3 },
1643     //{ 9, "CreateMessageQueue", "CreateMessageQueueStrictly", 0,            1 },
1644     { 9, "CreateRecursiveLock", "CreateRecursiveLockStrictly", 0,       1 },
1645     { 9, "CreateRecursiveLock", "CreateRecursiveLockStrictly", 0,       6 },    // old vx
1646     { 9, "CreateEventFlag", "CreateEventFlagStrictly", 0,               1 },
1647     { 9, "_GetSystemTime", "PT_GetSystemTime", 0,                       3 },
1648     { 9, "close", "Close", 0,                                              2 },
1649     { 9, "open", "Open", 0,                                                3 },
1650     { 9, "open", "Open", 0,                                                3 },
1651     { 9, "malloc_alt", "wrapped_malloc", 0,                                2 },
1652 
1653     //                                                                   ???
1654     { 11, "err_init_task", "\n-- %s() error in init_task() --", 0,         2 },
1655     { 11, "set_control_event", "Button:0x%08X:%s", 0x01000001,            14 },
1656     { 11, "set_control_event", "Button:0x%08X:%s", 0xf1000001,            15 },
1657     { 11, "set_control_event", "Button:0x%08X:%s", 0x01000001,            19 },
1658     { 11, "set_control_event", "Button:0x%08X:%s", 0x01000001,            20 },
1659     { 11, "_log", (char*)log_test, 0x01000001,                             1 },
1660     { 11, "_uartr_req", "A/uartr.req", 0,                                  3 },
1661 
1662     //                                                                   ???
1663     //{ 12, "DeleteFile_Fut", "DeleteFile_Fut", 1,                        0x38 },
1664     //{ 12, "AllocateUncacheableMemory", "AllocateUncacheableMemory", 1,  0x2C },
1665     //{ 12, "FreeUncacheableMemory", "FreeUncacheableMemory", 1,          0x30 },
1666     //{ 12, "free", "free", 1,                                            0x28 },
1667     //{ 12, "malloc", "malloc", 0x01000003,                               0x24 },
1668     //{ 12, "TakeSemaphore", "TakeSemaphore", 1,                          0x14 },
1669     //{ 12, "GiveSemaphore", "GiveSemaphore", 1,                          0x18 },
1670     //{ 12, "ClearEventFlag", "ClearEventFlag", 1,                        0x04 },
1671     //{ 12, "SetEventFlag", "SetEventFlag", 1,                            0x08 },
1672     //{ 12, "WaitForAnyEventFlag", "WaitForAnyEventFlag", 1,              0x0c },
1673     //{ 12, "WaitForAllEventFlag", "WaitForAllEventFlag", 1,              0x10 },
1674 
1675     { 13, "strftime", "Sunday", 1 },
1676 
1677     { 15, "LocalTime", "%04d:%02d:%02d %02d:%02d:%02d", 0x01000001 },
1678     { 15, "GetMemInfo", "Malloc Information\n", 0x01000001 },
1679     { 15, "GetMemInfo", "Malloc Information (%s type)\n", 0x01000001 },
1680     { 15, "vsprintf", "\nCPrintf Size Over!!", 0x01000001 },
1681     //{ 15, "ReadFastDir", "ReadFast_ERROR\n", 0x01000001 },
1682     //{ 15, "OpenFastDir", "OpenFastDir_ERROR\n", 0x01000001 },
1683     { 15, "realloc", "fatal error - scanner input buffer overflow", 0x01000001 },
1684     { 15, "CreateBinarySemaphore", "SdPower.c", 0x01000001 },
1685     { 15, "CreateBinarySemaphore", "DoWBForEVFOnce CreateBinarySemaphore Error\r\n", 0x01000001 }, // old Vx
1686     { 15, "CreateBinarySemaphore", "DoWBForEVFOnce CreateBinarySemaphore Error\n", 0x01000001 }, // old Vx
1687     //                                                                           Vx
1688     { 15, "SetHPTimerAfterTimeout", "FrameRateGenerator.c", 0x01000001,          0x0008 },
1689     { 15, "wrapped_malloc", "\n malloc error \n", 0x01000001,                    0x0010 },
1690     { 15, "IsStrobeChargeCompleted", "\r\nCaptSeq::ChargeNotCompleted!!", 0x01000001 }, // ixus30, 40
1691     { 15, "get_resource_pointer", "Not found icon resource.\r\n", 0x01000001,    0x0008 },
1692     { 15, "get_nd_value", "IrisSpecification.c", 0x01000001,                     0x0014 },
1693     { 15, "ImagerActivate", "Fail ImagerActivate(ErrorCode:%x)\r", 0x01000001,   0x0007 },
1694     { 15, "DoMovieFrameCapture", "DoMovieFrameCapture executed.",  0x01000001,   0x0007 },
1695 
1696     { 16, "DeleteDirectory_Fut", (char*)DeleteDirectory_Fut_test, 0x01000001 },
1697     { 16, "MakeDirectory_Fut", (char*)MakeDirectory_Fut_test, 0x01000001 },
1698     { 16, "RenameFile_Fut", (char*)RenameFile_Fut_test, 0x01000001 },
1699 
1700     { 17, "ScreenLock", "StartRecModeMenu", 0 },
1701     { 17, "ScreenUnlock", "StartRecModeMenu", 0 },
1702 
1703     // Ensure ordering in func_names is correct for dependencies here
1704     //                                                                           Vx
1705     { 19, "CreateMessageQueueStrictly", "CreateTaskStrictly", 0,                 0x0210 },
1706     { 19, "CreateMessageQueueStrictly", "CreateTaskStrictly", 0,                 0x0720 }, // old vx
1707     { 19, "CreateEventFlagStrictly", "CreateMessageQueueStrictly", 0,            0x010b },
1708     { 19, "CreateEventFlagStrictly", "CreateMessageQueueStrictly", 0,            0x0619 }, // old vx
1709     { 19, "CreateBinarySemaphoreStrictly", "CreateEventFlagStrictly", 0,         0x010b },
1710     { 19, "CreateBinarySemaphoreStrictly", "CreateEventFlagStrictly", 0,         0x081b }, // old vx
1711     { 19, "CreateCountingSemaphoreStrictly", "CreateBinarySemaphoreStrictly", 0, 0x010b },
1712     { 19, "CreateCountingSemaphoreStrictly", "CreateBinarySemaphoreStrictly", 0, 0x081b }, // old vx
1713     { 19, "CreateRecursiveLockStrictly", "CreateCountingSemaphoreStrictly", 0,   0x010b },
1714     { 19, "CreateRecursiveLockStrictly", "CreateCountingSemaphoreStrictly", 0,   0x071a }, // old vx
1715     //{ 19, "PostMessageQueue", "TryReceiveMessageQueue", 0,                       0x091f },
1716     //{ 19, "DeleteMessageQueue", "CreateMessageQueue", 0,                         0x1021 },
1717     //{ 19, "ReceiveMessageQueue", "DeleteMessageQueue", 0,                        0x1024 },
1718     //{ 19, "TryReceiveMessageQueue", "ReceiveMessageQueue", 0,                    0x002b },
1719     { 19, "TryPostMessageQueue", "PostMessageQueue", 0,                          0x058a },
1720     { 19, "GetNumberOfPostedMessages", "TryPostMessageQueue", 0,                 0x004b },
1721     { 19, "DeleteRecursiveLock", "CreateRecursiveLock", 0,                       0x0247 },
1722     { 19, "AcquireRecursiveLock", "DeleteRecursiveLock", 0,                      0x0136 }, // old vx
1723     { 19, "AcquireRecursiveLock", "DeleteRecursiveLock", 0,                      0x0026 }, // new vx
1724     { 19, "ReleaseRecursiveLock", "AcquireRecursiveLock", 0,                     0x154a }, // old vx
1725     { 19, "ReleaseRecursiveLock", "AcquireRecursiveLock", 0,                     0x002a }, // new vx
1726     { 19, "GetEventFlagValue", "ClearEventFlag", 0,                              0x0014 },
1727     //{ 19, "DeleteEventFlag", "CreateEventFlag", 0,                               0x0016 },
1728     { 19, "CheckAnyEventFlag", "CheckAllEventFlag", 0,                          -0x0004 },
1729     { 19, "CheckAllEventFlag", "WaitForEventFlag", 0,                           -0x1028 },
1730     { 19, "WaitForAnyEventFlag", "WaitForEventFlag", 0,                          0x0569 },
1731     { 19, "WaitForAllEventFlag", "WaitForAnyEventFlag", 0,                       0x1004 },
1732     { 19, "ClearEventFlag", "SetEventFlag", 0,                                   0x0167 }, // new vx
1733     { 19, "ClearEventFlag", "SetEventFlag", 0,                                   0x0165 }, // old vx
1734     { 19, "SetEventFlag", "WaitForAllEventFlag", 0,                              0x1004 },
1735     { 19, "TryTakeSemaphore", "GiveSemaphore", 0,                               -0x0619 }, // old vx
1736     { 19, "TryTakeSemaphore", "GiveSemaphore", 0,                               -0x071c }, // new vx
1737     { 19, "GetSemaphoreValue", "GiveSemaphore", 0,                               0x0035 }, // old vx
1738     { 19, "GetSemaphoreValue", "GiveSemaphore", 0,                               0x013b }, // new vx
1739     { 19, "SetHPTimerAfterNow", "SetHPTimerAfterTimeout", 0,                    -0x0223 },
1740     { 19, "CancelHPTimer", "SetHPTimerAfterTimeout", 0,                          0x09fa },
1741     { 19, "SetTimerAfter", "_GetSystemTime", 0,                                  0x0355 },
1742     { 19, "SetTimerWhen", "SetTimerAfter", 0,                                    0x0327 },
1743     { 19, "CancelTimer", "SetTimerWhen", 0,                                      0x026d }, // older vx
1744     { 19, "CancelTimer", "SetTimerWhen", 0,                                      0x021e }, // newer vx (no unused functions inbetween)
1745 
1746     { 19, "UnregisterInterruptHandler", "RegisterInterruptHandler", 0,           0x0909 },
1747     { 19, "GetSRAndDisableInterrupt", "UnregisterInterruptHandler", 0,           0x0f06 },
1748     { 19, "SetSR", "GetSRAndDisableInterrupt", 0,                                0x1003 },
1749     { 19, "EnableInterrupt", "SetSR", 0,                                         0x1508 },
1750     //{ 19, "UnregisterInterruptHandler", "RegisterInterruptHandler", 0,           0x0009 },
1751     //{ 19, "GetSRAndDisableInterrupt", "UnregisterInterruptHandler", 0,           0x0006 },
1752     //{ 19, "SetSR", "UnregisterInterruptHandler", 0,                              0x1007 },
1753     //{ 19, "EnableInterrupt", "UnregisterInterruptHandler", 0,                    0x170f },
1754     { 19, "GetDrive_TotalClusters", "GetDrive_FreeClusters", 0,                 -0x120f },
1755     { 19, "GetDrive_TotalClusters", "GetDrive_FreeClusters", 0,                 -0x130f }, // s80
1756     { 19, "GetDrive_TotalClusters", "GetDrive_FreeClusters", 0,                 -0x120e }, // ixus950
1757     { 19, "GetDrive_TotalClusters", "GetDrive_FreeClusters", 0,                 -0x1310 }, // old vx
1758     { 19, "GetDrive_ClusterSize", "GetDrive_TotalClusters", 0,                  -0x020f },
1759     { 19, "GetDrive_ClusterSize", "GetDrive_TotalClusters", 0,                  -0x0217 }, // s80
1760     { 19, "GetDrive_ClusterSize", "GetDrive_TotalClusters", 0,                  -0x0310 }, // old vx
1761 
1762     { 21, "add_ptp_handler", (char*)find_add_ptp_handler, 0 },
1763     //{ 21, "apex2us", (char*)find_apex2us, 0 },
1764     { 21, "mkdir", (char*)find_mkdir, 0 },
1765     { 21, "_pow", (char*)find_pow, 0 },
1766     { 21, "_log", (char*)find_log, 0 },
1767     { 21, "_log10", (char*)find_log10, 0 },
1768     { 21, "get_ptp_file_buf", (char*)find_get_ptp_file_buf, 0 },
1769 
1770     { 22, "closedir", (char*)find_closedir, 0 },
1771     { 22, "PT_PlaySound", (char*)find_PT_PlaySound, 0 },
1772     { 22, "ExportToEventProcedure_FW", (char*)find_ExportToEventProcedure, 0 },
1773     { 22, "RegisterEventProcedure_FW", (char*)find_RegisterEventProcedure, 0 },
1774 
1775     { 22, "set_control_event", (char*)find_set_control_event, 0 }, // vx
1776     { 22, "filesem_init", (char*)find_filesem_init, 0 }, // vx
1777     { 22, "GetCurrentMachineTime", (char*)find_getcurrentmachinetime, 0},
1778     { 22, "get_nd_value", (char*)find_get_nd_value, 0},
1779     { 22, "get_current_nd_value", (char*)find_get_current_nd_value, 0},
1780     { 22, "GetBaseSv", (char*)find_GetBaseSv, 0},
1781     { 22, "exmem_free", (char*)find_exmem_free, 0},
1782     { 22, "exmem_alloc", (char*)find_exmem_alloc, 0},
1783     { 22, "get_ptp_buf_size", (char*)find_get_ptp_buf_size, 0},
1784 
1785     //                                                                                          Vx
1786     { 100, "DebugAssert", "\nAssert: File %s Line %d\n", 0,                                     10 },
1787     { 100, "DebugAssert", "\aAssert: File %s,  Expression %s,  Line %d\n", 0,                   14 }, // ixus30,40
1788     { 100, "CreateMessageQueue", "CreateMessageQueue : call from interrupt handler", 0,         8 },
1789     { 100, "DeleteMessageQueue", "DeleteMessageQueue : call from interrupt handler", 0,         8 },
1790     { 100, "PostMessageQueue", "PostMessageQueue : call from interrupt handler", 0,             12 },
1791     { 100, "ReceiveMessageQueue", "ReceiveMessageQueue : NULL buffer address", 0,               11 },
1792     { 100, "TryReceiveMessageQueue", "TryReceiveMessageQueue : NULL buffer address", 0,         10 },
1793     { 100, "CreateEventFlag", "CreateEventFlag : call from interrupt handler", 0,               5 },
1794     { 100, "DeleteEventFlag", "DeleteEventFlag : call from interrupt handler", 0,               8 },
1795     { 100, "WaitForEventFlag", "WaitForEventFlag : call from interrupt handler", 0,             12 },
1796     { 100, "CancelHPTimer", "EventProcedure", 0,                                                101 }, // newest vx
1797     { 100, "get_current_exp", "Exp  Av %d, Tv %d, Gain %d\r",0x01000001,                        0x07 },
1798     
1799     { 101, "DeleteSemaphore", "DeleteSemaphore", 0 },
1800     { 101, "CreateCountingSemaphore", "CreateCountingSemaphore", 0 },
1801     { 101, "TakeSemaphore", "TakeSemaphore", 0 },
1802     { 101, "GiveSemaphore", "GiveSemaphore", 0 },
1803     { 101, "CreateTask", "CreateTask", 0 },
1804     { 101, "ExitTask", "ExitTask", 0 },
1805     { 101, "PT_GetSystemTime", "PT_GetSystemTime", 0 },
1806 
1807     { 102, "PB2Rec", "AC:PB2Rec", 0,                                                            0x20 },
1808     { 102, "Rec2PB", "AC:Rec2PB", 0,                                                            0x20 },
1809     { 102, "MenuIn", "SSAPI::MenuIn", 0,                                                        0x20 },
1810     { 102, "MenuOut", "SSAPI::MenuOut", 0,                                                      0x20 },
1811 
1812     { 103, "GetDrive_FreeClusters", "AvailClusters.c", 0,                                       0x04 },
1813 
1814     { 104, "SetLogicalEventActive", "EventReciever.c", 16,                                      0x0000 },
1815 
1816     { 0, 0, 0, 0 }
1817 };
1818 
1819 // Find the named function in the 'func_list' array above, return index of entry
1820 int find_func(const char* name)
1821 {
1822     int i;
1823     for (i=0; func_list[i].name != 0; i++)
1824     {
1825         if (strcmp(name, func_list[i].name) == 0)
1826         {
1827             return i;
1828         }
1829     }
1830     return -1;  // Not found
1831 }
1832 
1833 // Get VxWorks version specific offset?
1834 int vxworks_offset(firmware *fw, string_sig *sig)
1835 {
1836     return sig->vxworks_offset;
1837 }
1838 
1839 //------------------------------------------------------------------------------------------------------------
1840 
1841 // Loop through firmware looking for instances of a sig string
1842 // For each one found call the check_match function to see if it matches the sig
1843 // Return 1 if match found, else return 0
1844 int fw_string_process(firmware *fw, string_sig *sig, int (*check_match)(firmware *fw, string_sig *sig, int j), int inc_eos)
1845 {
1846     int nlen = strlen(sig->ev_name);
1847     uint32_t nm0 = *((uint32_t*)sig->ev_name);
1848     uint32_t *p;
1849     int j;
1850     BufRange *br;
1851 
1852     for (br = fw->br; br != 0; br = br->next)
1853     {
1854         for (p = br->p, j = br->off; j < br->off+br->len-nlen/4; p++, j++)
1855         {
1856             if ((nm0 == *p) && (memcmp(p+1,sig->ev_name+4,nlen-4+inc_eos) == 0))
1857             {
1858                 if (check_match(fw,sig,j))
1859                     return 1;
1860             }
1861         }
1862     }
1863 
1864     return 0;
1865 }
1866 
1867 // As above; but scan the firmware byte-by-byte rather than by words
1868 // Slower; but required when strings are not stores on 32 bit boundaries
1869 int fw_string_process_unaligned(firmware *fw, string_sig *sig, int (*check_match)(firmware *fw, string_sig *sig, int j))
1870 {
1871     int nlen = strlen(sig->ev_name);
1872     char *p;
1873     int j;
1874     BufRange *br;
1875 
1876     for (br = fw->br; br != 0; br = br->next)
1877     {
1878         for (p = (char*)br->p, j = 0; j < br->len*4-nlen; p++, j++)
1879         {
1880             if (strcmp(p,sig->ev_name) == 0)
1881             {
1882                 if (check_match(fw,sig,j+br->off*4))
1883                     return 1;
1884             }
1885         }
1886     }
1887 
1888     return 0;
1889 }
1890 
1891 // Loop through the firmware from the start, calling 'check_match' for each location
1892 // If 'check_match' returns non-zero, exit returning 1.
1893 // Otherwise returns 0 - no match found.
1894 int fw_process(firmware *fw, string_sig *sig, int (*check_match)(firmware *fw, string_sig *sig, int j))
1895 {
1896     uint32_t *p;
1897     int j;
1898     BufRange *br;
1899 
1900     for (br = fw->br; br != 0; br = br->next)
1901     {
1902         for (p = br->p, j = br->off; j < br->off+br->len; p++, j++)
1903         {
1904             if (check_match(fw,sig,j))
1905                 return 1;
1906         }
1907     }
1908 
1909     return 0;
1910 }
1911 
1912 //------------------------------------------------------------------------------------------------------------
1913 
1914 // New string / signature matching functions
1915 
1916 // Sig pattern:
1917 //      Function pointer    -   DCD func
1918 //      String              -   DCB "func"
1919 // Note: 'func' may not be the target address, the sig->offset value allows selection of another function
1920 //       called at a fixed number of instructions from the 'func' address found
1921 int match_strsig1(firmware *fw, string_sig *sig, int j)
1922 {
1923     uint32_t fadr = fwval(fw,j-1);      // function address
1924     if (idx_valid(fw,adr2idx(fw,fadr))) // is function address valid
1925     {
1926         // If function address is a B, and we are following branches, then follow the first B
1927         if (sig->offset > 1) fadr = followBranch(fw, fadr, 1);
1928         // Follow any subsequent branch at the given offset
1929         fadr = followBranch2(fw, fadr, sig->offset);
1930         fwAddMatch(fw,fadr,32,0,101);
1931         return 1;
1932     }
1933     return 0;
1934 }
1935 
1936 // Sig pattern:
1937 //      String pointer      -       DCD str
1938 //      Function pointer    -       DCD func
1939 //                ...
1940 //      String              -   str DCB "func"
1941 // Note: 'func' may not be the target address, the offset value allows selection of another function
1942 //       called at a fixed number of instructions from the 'func' address found
1943 int match_strsig2a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
1944 {
1945     if (fwval(fw,k) == sadr)                // pointer to string?
1946     {
1947         uint32_t fadr = fwval(fw,k+1);      // function address
1948         if (idx_valid(fw,adr2idx(fw,fadr))) // is function address valid
1949         {
1950             uint32_t bfadr = followBranch2(fw, fadr, offset);
1951             if ((offset <= 1) || (bfadr != fadr))
1952             {
1953                 fwAddMatch(fw,bfadr,32,0,102);
1954                 return 1;
1955             }
1956         }
1957     }
1958     return 0;
1959 }
1960 int match_strsig2(firmware *fw, string_sig *sig, int j)
1961 {
1962     // Note - 'j' is byte offset in firmware not instruction index (called from fw_string_process_unaligned)
1963     return search_fw(fw, match_strsig2a, fw->base + j, sig->offset, 2);
1964 }
1965 
1966 // Sig pattern:
1967 //      Load Func Address   -   ADR Rx, func
1968 //      Load String Address -   ADR Rx, "func"
1969 //      Branch              -   BL
1970 //              ...
1971 //      String              -   DCB "func"
1972 // or
1973 //      Load Func Address   -   ADR Rx, func
1974 //                              B   loc
1975 //              ...
1976 //                          loc:
1977 //      Load String Address -   ADR    Rx, "func"
1978 //      Branch              -   BL
1979 //              ...
1980 //      String              -   DCB "func"
1981 // 'sadr' = address of "func" string
1982 // Note: 'func' may not be the target address, the offset value allows selection of another function
1983 //       called at a fixed number of instructions from the 'func' address found
1984 int match_strsig3a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
1985 {
1986     if (isADR_PC(fw,k+1) &&    // ADR ?
1987         isBorBL(fw,k+2))       // B or BL ?
1988     {
1989         uint32_t padr = ADR2adr(fw,k+1);    // get address pointed to by 2nd ADR instructioin
1990         if (padr == sadr)                   // does it match target string
1991         {
1992             int j2 = k;
1993             int found = 0;
1994             if (isADR_PC(fw,k))             // ADR ?
1995                 found = 1;
1996             else
1997             {
1998                 // May be DCD block between 1st and 2nd ADR
1999                 for (j2 = k-2; j2 >= 0 && j2 >= k-4096; j2--)
2000                 {
2001                     if (isADR_PC(fw,j2) &&  // ADR ?
2002                         isB(fw,j2+1))       // B
2003                     {
2004                         uint32_t fa = idx2adr(fw,j2+1);
2005                         fa = followBranch(fw,fa,1);
2006                         if (adr2idx(fw,fa) == k+1)
2007                         {
2008                             found = 1;
2009                             break;
2010                         }
2011                     }
2012                 }
2013             }
2014             if (found)
2015             {
2016                 uint32_t fadr = ADR2adr(fw,j2);
2017                 if (offset > 1) fadr = followBranch(fw, fadr, 1);
2018                 fadr = followBranch2(fw, fadr, offset);
2019                 fwAddMatch(fw,fadr,32,0,103);
2020                 return 1;
2021             }
2022         }
2023     }
2024     return 0;
2025 }
2026 int match_strsig3(firmware *fw, string_sig *sig, int j)
2027 {
2028     return search_fw(fw, match_strsig3a, idx2adr(fw,j), sig->offset, 3);
2029 }
2030 
2031 // Sig pattern:
2032 //      Save Regs           -   STMFD
2033 //                ... (offset)
2034 //      Load String Address -   ADR Rx, "func"
2035 //                ...
2036 //      String              -   DCB "func"
2037 int match_strsig4a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
2038 {
2039     if (isSTMFD(fw,k) &&        // STMFD
2040         isADR_PC(fw,k+offset))  // ADR ?
2041     {
2042         uint32_t padr = ADR2adr(fw,k+offset);
2043         if (padr == sadr)
2044         {
2045             uint32_t fadr = idx2adr(fw,k);
2046             fwAddMatch(fw,fadr,32,0,104);
2047             return 1;
2048         }
2049     }
2050     return 0;
2051 }
2052 int match_strsig4(firmware *fw, string_sig *sig, int j)
2053 {
2054     return search_fw(fw, match_strsig4a, idx2adr(fw,j), sig->offset, sig->offset+1);
2055 }
2056 
2057 // Sig pattern:
2058 //      Load Func Address   -   LDR Rx, =func
2059 //      Load String Address -   xDR Rx, "func"  (LDR or ADR)
2060 //      Branch              -   BL
2061 //              ...
2062 //      String              -   DCB "func"
2063 // or
2064 //      Load Func Address   -   LDR Rx, =func
2065 //                              B   loc
2066 //              ...
2067 //                          loc:
2068 //      Load String Address -   xDR Rx, "func"  (LDR or ADR)
2069 //      Branch              -   BL
2070 //              ...
2071 //      String              -   DCB "func"
2072 static int dryos_ofst;
2073 int match_strsig5a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
2074 {
2075     if ((isADR_PC(fw,k+1) || isLDR_PC(fw,k+1)) &&   // LDR or ADR ?
2076         isBorBL(fw,k+2))                            // B or BL ?
2077     {
2078         uint32_t padr;
2079         if (isLDR_PC(fw,k+1))                       // LDR ?
2080             padr = LDR2val(fw,k+1);
2081         else
2082             padr = ADR2adr(fw,k+1);
2083         if (padr == sadr)
2084         {
2085             int j2 = k;
2086             int found = 0;
2087             if (isLDR_PC(fw,k))                     // LDR ?
2088                 found = 1;
2089             else
2090             {
2091                 for (j2 = k-2; j2 >= 0 && j2 >= k-4096; j2--)
2092                 {
2093                     if (isLDR_PC(fw,j2) &&  // LDR ?
2094                         isB(fw,j2+1))       // B
2095                     {
2096                         if (idxFollowBranch(fw,j2+1,1) == k+1)
2097                         {
2098                             found = 1;
2099                             break;
2100                         }
2101                     }
2102                 }
2103             }
2104             if (found)
2105             {
2106                 uint32_t fadr = LDR2val(fw,j2);
2107                 if (offset > 1) fadr = followBranch(fw, fadr, 1);
2108                 fadr = followBranch2(fw, fadr, offset);
2109                 if (dryos_ofst != 0)
2110                 {
2111                     uint32_t fadr2 = followBranch(fw, fadr, dryos_ofst);
2112                     if (fadr == fadr2) return 0;
2113                     fadr = fadr2;
2114                 }
2115                 fwAddMatch(fw,fadr,32,0,105);
2116                 return 1;
2117             }
2118         }
2119     }
2120     return 0;
2121 }
2122 int match_strsig5(firmware *fw, string_sig *sig, int j)
2123 {
2124     dryos_ofst = vxworks_offset(fw,sig);
2125     return search_fw(fw, match_strsig5a, idx2adr(fw,j), sig->offset, 3);
2126 }
2127 
2128 // Sig pattern:
2129 //    Function immediately preceeding string
2130 int match_strsig6(firmware *fw, string_sig *sig, int j)
2131 {
2132     int j1 = find_inst_rev(fw, isSTMFD_LR, j-1, j-1);
2133     if (j1 > 0)
2134     {
2135         uint32_t fadr = idx2adr(fw,j1);
2136         fwAddMatch(fw,fadr,32,0,106);
2137         return 1;
2138     }
2139 
2140     return 0;
2141 }
2142 
2143 // Sig pattern:
2144 //      Str ref -   xDRnn Rx, =str_ptr
2145 //            ...
2146 //                  BL  func
2147 //            ...
2148 //      String      DCB "str"
2149 int match_strsig7a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
2150 {
2151     if (isADR_PC_cond(fw,k) || isLDR_PC_cond(fw,k)) // LDR or ADR ?
2152     {
2153         uint32_t padr;
2154         if (isLDR_PC_cond(fw,k)) // LDR ?
2155             padr = LDR2val(fw,k);
2156         else
2157             padr = ADR2adr(fw,k);
2158         if (padr == sadr)
2159         {
2160             int j2 = find_inst(fw, isBL, k+1, 10);
2161             if (j2 > 0)
2162             {
2163                 uint32_t fa = idx2adr(fw,j2);
2164                 fa = followBranch2(fw,fa,offset);
2165                 fwAddMatch(fw,fa,32,0,107);
2166                 return 1;
2167             }
2168         }
2169     }
2170     return 0;
2171 }
2172 int match_strsig7(firmware *fw, string_sig *sig, int j)
2173 {
2174     return search_fw(fw, match_strsig7a, idx2adr(fw,j), sig->offset, 2);
2175 }
2176 
2177 // Sig pattern:
2178 //      Special case for WriteSDCard
2179 int ofst;
2180 int match_strsig8(firmware *fw, string_sig *sig, int j)
2181 {
2182     int j1;
2183     for (j1=j-2; j1<j+8; j1++)
2184     {
2185         uint32_t fadr = idx2adr(fw,j1);
2186         if (fwval(fw,j1) >= fw->base)   // pointer ??
2187         {
2188             int j2;
2189             for (j2=j1-1; j2>=j1-1000 && j2>=0; j2--)
2190             {
2191                 if (isLDR_PC(fw,j2) && (LDR2adr(fw,j2) == fadr))    // LDR ?
2192                 {
2193                     if ((isSTR(fw,j2+1) && (fwOp2(fw,j2+1) == ofst)) ||    // STR ?
2194                         (isSTR(fw,j2+2) && (fwOp2(fw,j2+2) == ofst)))      // STR ?
2195                     {
2196                         fadr = fwval(fw,j1);
2197                         if (idx_valid(fw,adr2idx(fw,fadr)))
2198                         {
2199                             fwAddMatch(fw,fadr,32,0,108);
2200                             return 1;
2201                         }
2202                     }
2203                 }
2204             }
2205         }
2206     }
2207 
2208     return 0;
2209 }
2210 int find_strsig8(firmware *fw, string_sig *sig)
2211 {
2212     uint32_t fadr = 0;
2213     int srch = 20;
2214 
2215     // Find "UpdateMBROnFlash" code
2216     int j = get_saved_sig(fw,"UpdateMBROnFlash");
2217     if (j >= 0)
2218     {
2219         fadr = func_names[j].val;
2220     }
2221     else
2222     {
2223         j = get_saved_sig(fw,"MakeSDCardBootable");
2224         if (j >= 0)
2225         {
2226             fadr = func_names[j].val;
2227             srch = 32;
2228         }
2229     }
2230 
2231     if (fadr == 0) return 0;
2232 
2233     int idx = adr2idx(fw, fadr);
2234     ofst = -1;
2235 
2236     for (j=idx+srch; j<idx+srch+12; j++)
2237     {
2238         if (isLDR(fw,j) && isLDR(fw,j+1) && isLDR(fw,j+2))
2239         {
2240             ofst = fwOp2(fw,j) + fwOp2(fw,j+1) + fwOp2(fw,j+2);
2241             break;
2242         }
2243     }
2244 
2245     if (ofst == -1) return 0;
2246 
2247     return fw_string_process(fw, sig, match_strsig8, 1);
2248 }
2249 
2250 // Sig pattern:
2251 //      Func is B/BL @ offset from previous found func
2252 //          prev_func
2253 //              ... (offset)
2254 //              BL    func
2255 int find_strsig9(firmware *fw, string_sig *sig)
2256 {
2257     int j = get_saved_sig(fw,sig->ev_name);
2258     if (j >= 0)
2259     {
2260         if (func_names[j].val != 0)
2261         {
2262             int ofst = vxworks_offset(fw, sig);
2263             uint32_t fadr = followBranch(fw, func_names[j].val+ofst*4, 0xF1000001);
2264             if ((sig->offset == -1) || (fadr != func_names[j].val+ofst*4))
2265             {
2266                 uint32_t fadr2 = fadr;
2267                 if (sig->offset != -1) fadr2 = followBranch2(fw, fadr2, sig->offset);
2268                 if ((sig->offset <= 0) || (fadr2 != fadr))
2269                 {
2270                     fwAddMatch(fw,fadr2,32,0,109);
2271                     return 1;
2272                 }
2273             }
2274         }
2275     }
2276 
2277     return 0;
2278 }
2279 
2280 // Sig pattern:
2281 //      Func            -   func
2282 //            .... (offset)
2283 //      Ref to string   -       ADR Rx, str
2284 //            ....
2285 //      String          -       DCB "str"
2286 int match_strsig11(firmware *fw, string_sig *sig, int j)
2287 {
2288     int ofst = vxworks_offset(fw, sig);
2289 
2290     uint32_t sadr = idx2adr(fw,j);        // string address
2291     int j1;
2292     for (j1 = j-1; j1 >= 0; j1--)
2293     {
2294         if (isADR_PC_cond(fw,j1))   // ADR ?
2295         {
2296             uint32_t padr = ADR2adr(fw,j1);
2297             if (padr == sadr)
2298             {
2299                 uint32_t fadr = idx2adr(fw,j1-ofst);
2300                 uint32_t bfadr = followBranch(fw,fadr,sig->offset);
2301                 // special case for 'set_control_event'
2302                 int found = 0;
2303                 if (strcmp(sig->name,"set_control_event") == 0)
2304                 {
2305                     int j2 = j1 - ofst;
2306                     if (isBL_cond(fw,j2) &&                                             // BLxx
2307                         isLDR_SP(fw,j2+1) && (fwRd(fw,j2+1) == 0) &&                    // LDR R0,[SP,x]
2308                         isBL(fw,j2+2) &&                                                // BL
2309                         isMOV(fw,j2+3) && (fwRd(fw,j2+3) == 4) && (fwRn(fw,j2+3) == 0)) // LDR R4, R0
2310                     {
2311                         found = 1;
2312                     }
2313                 }
2314                 else
2315                     found = 1;
2316                 if (found && ((sig->offset == 0) || (bfadr != fadr)))
2317                 {
2318                     fwAddMatch(fw,bfadr,32,0,111);
2319                     return 1;
2320                 }
2321             }
2322         }
2323     }
2324 
2325     return 0;
2326 }
2327 
2328 //// Sig pattern:
2329 ////      Func is referenced in 'CreateJumptable'
2330 ////          LDR R1, =func
2331 ////          STR R1, [R0,nnn]
2332 ////      nnn - dryos version dependant offset
2333 //int find_strsig12(firmware *fw, string_sig *sig)
2334 //{
2335 //    int j = get_saved_sig(fw,"CreateJumptable");
2336 //
2337 //    int ofst = vxworks_offset(fw, sig);
2338 //
2339 //    if (ofst == 0) return 0;
2340 //
2341 //    if (j >= 0)
2342 //    {
2343 //        if (func_names[j].val != 0)
2344 //        {
2345 //            int idx = adr2idx(fw, func_names[j].val);
2346 //            for(; !isBX_LR(fw,idx); idx++)  // BX LR
2347 //            {
2348 //                if (((fwval(fw,idx+1) & 0xFFFFF000) == 0xE5801000) && // STR R1,[R0,nnn]
2349 //                    (fwOp2(fw,idx+1) == ofst))
2350 //                {
2351 //                    uint32_t fadr = LDR2val(fw,idx);
2352 //                    uint32_t bfadr = followBranch2(fw,fadr,sig->offset);
2353 //                    if ((sig->offset <= 1) || ((bfadr != fadr) && ((fw->buf[adr2idx(fw,fadr)] & 0xFFFF0000) == 0xE92D0000)))
2354 //                    {
2355 //                        fwAddMatch(fw,bfadr,32,0,112);
2356 //                        return 1;
2357 //                    }
2358 //                }
2359 //                else if (isB(fw,idx))    // B
2360 //                {
2361 //                    idx = adr2idx(fw,followBranch(fw,idx2adr(fw,idx),1)) - 1;
2362 //                }
2363 //            }
2364 //        }
2365 //    }
2366 //
2367 //    return 0;
2368 //}
2369 
2370 // Sig pattern:
2371 //      Func    -   func
2372 //          ... (offset)
2373 //      Str ref -       LDR Rx, =str_ptr
2374 //          ...
2375 //      Str ptr -       DCD str_ptr
2376 //          ...
2377 //      Str ptr -   str_ptr
2378 //                      DCD str
2379 //          ...
2380 //      String          DCB "str"
2381 int match_strsig13a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
2382 {
2383     if (fwval(fw,k) == sadr)    // string ptr
2384     {
2385         uint32_t padr = idx2adr(fw,k);      // string ptr address
2386         int j2;
2387         for (j2 = k-1; j2 >= 0; j2--)
2388         {
2389             if (fwval(fw,j2) == padr)       // string ptr address
2390             {
2391                 uint32_t ppadr = idx2adr(fw,j2);        // string ptr ptr address
2392                 int j3;
2393                 for (j3 = j2-1; j3 >= 0; j3--)
2394                 {
2395                     if (isLDR_PC(fw,j3) && (LDR2adr(fw,j3) == ppadr))
2396                     {
2397                         uint32_t fadr = idx2adr(fw,j3-offset);
2398                         fwAddMatch(fw,fadr,32,0,113);
2399                         return 1;
2400                     }
2401                 }
2402             }
2403         }
2404     }
2405     return 0;
2406 }
2407 int match_strsig13(firmware *fw, string_sig *sig, int j)
2408 {
2409     // Note - 'j' is offset in firmware not instruction index (called from fw_string_process_unaligned)
2410     return search_fw(fw, match_strsig13a, fw->base + j, sig->offset, 1);
2411 }
2412 
2413 // Sig pattern:
2414 //                  BL  func
2415 //            ...
2416 //      Str ref -   xDR Rx, =str_ptr
2417 //            ...
2418 //      String      DCB "str"
2419 // dryos_ofst: search range limit for the previous bl instruction
2420 int match_strsig15a(firmware *fw, int k, uint32_t sadr, uint32_t offset)
2421 {
2422     if (isADR_PC_cond(fw,k) || isLDR_PC_cond(fw,k))   // LDR or ADR ?
2423     {
2424         uint32_t padr;
2425         if (isLDR_PC_cond(fw,k)) // LDR ?
2426             padr = LDR2val(fw,k);
2427         else
2428             padr = ADR2adr(fw,k);
2429         if (padr == sadr)
2430         {
2431             int j2 = find_inst_rev(fw, isBL, k-1, dryos_ofst);
2432             if (j2 > 0)
2433             {
2434                 uint32_t fa = idx2adr(fw,j2);
2435                 fa = followBranch2(fw,fa,offset);
2436                 fwAddMatch(fw,fa,32,0,115);
2437                 return 1;
2438             }
2439         }
2440     }
2441     return 0;
2442 }
2443 int match_strsig15(firmware *fw, string_sig *sig, int j)
2444 {
2445     dryos_ofst = vxworks_offset(fw,sig);
2446     if (dryos_ofst == 0) dryos_ofst = 50;
2447     return search_fw(fw, match_strsig15a, idx2adr(fw,j), sig->offset, 1);
2448 }
2449 
2450 // Sig pattern:
2451 //      Function immediately preceeding usage of hex value
2452 int match_strsig16(firmware *fw, string_sig *sig, int j)
2453 {
2454     uint32_t nm0 = *((uint32_t*)sig->ev_name);
2455 
2456     if (isADR_PC_cond(fw,j) || isLDR_PC_cond(fw,j))   // LDR or ADR ?
2457     {
2458         uint32_t padr = 0;
2459         if (isLDR_PC_cond(fw,j)) // LDR ?
2460         {
2461             int k = adr2idx(fw,LDR2adr(fw,j));
2462             if (idx_valid(fw,k))
2463                 padr = fwval(fw,k);
2464         }
2465         else
2466             padr = ADR2adr(fw,j);
2467         if (padr == nm0)
2468         {
2469             int j2 = find_inst_rev(fw, isSTMFD_LR, j-1, 50);
2470             if (j2 > 0)
2471             {
2472                 uint32_t fa = idx2adr(fw,j2);
2473                 fwAddMatch(fw,fa,32,0,116);
2474                 return 1;
2475             }
2476         }
2477     }
2478 
2479     return 0;
2480 }
2481 
2482 // Sig pattern:
2483 //      Special case for ScreenLock & ScreenUnlock
2484 int find_strsig17(firmware *fw, string_sig *sig)
2485 {
2486     int j = get_saved_sig(fw,"StartRecModeMenu");
2487 
2488     if (j >= 0)
2489     {
2490         if (func_names[j].val != 0)
2491         {
2492             int idx = adr2idx(fw, func_names[j].val);
2493             int k = 0;
2494             if (isLDR_PC(fw,idx-3) && isMOV_immed(fw,idx-2) && isB(fw,idx-1))
2495             {
2496                 k = adr2idx(fw,LDR2val(fw,idx-3));
2497             }
2498             else if (isMOV_immed(fw,idx-3) && isADR_PC(fw,idx-2) && isB(fw,idx-1))
2499             {
2500                 k = adr2idx(fw,ADR2adr(fw,idx-2));
2501             }
2502             if (k != 0)
2503             {
2504                 uint32_t fadr;
2505                 if (strcmp(sig->name,"ScreenLock") == 0)
2506                     fadr = followBranch(fw,idx2adr(fw,k+1),0x01000001);
2507                 else
2508                 {
2509                     k = find_inst(fw, isLDMFD, k+1, 60);
2510                     fadr = followBranch(fw,idx2adr(fw,k-1),0x01000001);
2511                 }
2512                 fwAddMatch(fw,fadr,32,0,117);
2513                 return 1;
2514             }
2515         }
2516     }
2517 
2518     return 0;
2519 }
2520 
2521 // Sig pattern:
2522 //      Func is offset from previously found func
2523 //          prev_func
2524 //              ... (offset, less than 0xff)
2525 //          func
2526 // vxworks_offset to be encoded as: 0xQRPP
2527 // PP) offset, 0x00...0xff, in words
2528 // Q) 'previous instruction flag': 0 for LDMFD, 1 for B
2529 // R) 'additional gap size': 0x0 ... 0xf, to skip an additional gap, in words
2530 // offset is negative if vxworks_offset is negative
2531 int find_strsig19(firmware *fw, string_sig *sig)
2532 {
2533     int j = get_saved_sig(fw,sig->ev_name);
2534     if (j >= 0)
2535     {
2536         if (func_names[j].val != 0) // address, not idx
2537         {
2538             int ofst = vxworks_offset(fw, sig);
2539             int neg = 1;
2540             if (ofst<0)
2541             {
2542                 neg=-1;
2543                 ofst=-ofst;
2544             }
2545             int addoffs = (ofst & 0xf00)>>8;
2546             uint32_t fadr = func_names[j].val+neg*(ofst&0xff)*4;
2547             int k = 0;
2548             switch ((ofst&0xf000)>>12)
2549             {
2550                 case 0: k = isLDMFD_PC(fw, adr2idx(fw, fadr)-1-addoffs); break;
2551                 case 1: k = isB(fw, adr2idx(fw, fadr)-1-addoffs); break;
2552             }
2553             if (k)
2554             {
2555                 fwAddMatch(fw,fadr,32,0,119);
2556                 return 1;
2557             }
2558         }
2559     }
2560 
2561     return 0;
2562 }
2563 
2564 // Sig pattern (Vx specific?):
2565 //      Func            -   func
2566 //            .... (offset)
2567 //      Ref to string   -       LDR Rx, pstr
2568 //            ....
2569 //      Ptr to string   -       DCD pstr
2570 // based on method 11
2571 int match_strsig100(firmware *fw, string_sig *sig, int j)
2572 {
2573     int ofst = vxworks_offset(fw, sig);
2574 
2575     uint32_t sadr = idx2adr(fw,j);        // string address
2576     int j1;
2577     for (j1 = j+256; j1 >= 0; j1--)
2578     {
2579         if (isLDR(fw,j1))   // LDR ?
2580         {
2581             uint32_t pval = LDR2val(fw,j1);
2582             if (pval == sadr)
2583             {
2584                 uint32_t fadr = idx2adr(fw,j1-ofst);
2585                 uint32_t bfadr = followBranch(fw,fadr,sig->offset);
2586                 if ((sig->offset == 0) || (bfadr != fadr))
2587                 {
2588                     fwAddMatch(fw,bfadr,32,0,1100);
2589                     return 1;
2590                 }
2591             }
2592         }
2593     }
2594 
2595     return 0;
2596 }
2597 
2598 // Sig pattern (VxWorks specific):
2599 // still needed due to ambiguous parts of code (indirect ExportToEventProcedure, RegisterEventProcedure calls)
2600 //      String               -   DCB "func"
2601 //              ...
2602 //      Load String Address  -   LDR R0, ="func"
2603 //      Load func Address    -   LDR R1, =func
2604 // these are parameters for ExportToEventProcedure, RegisterEventProcedure
2605 int match_strsig101(firmware *fw, string_sig *sig, int j)
2606 {
2607     uint32_t sadr = idx2adr(fw,j);        // string address
2608     int j1;
2609     for (j1 = j+1024; j1 >= 0; j1--)
2610     {
2611         if (isLDR(fw,j1) && (fwRd(fw,j1)==0))   // LDR R0,
2612         {
2613             uint32_t pval = LDR2val(fw,j1);
2614             if (pval == sadr) // our string's address
2615             {
2616                 int j2;
2617                 for (j2 = j1+2; j2 > j1; j2--)
2618                 {
2619                     if (isLDR(fw,j2) && (fwRd(fw,j2)==1)) // LDR R1,
2620                     {
2621                         uint32_t pval2 = LDR2val(fw,j2);
2622                         fwAddMatch(fw,pval2,32,0,1101);
2623                         return 1;
2624                     }
2625                 }
2626             }
2627         }
2628     }
2629 
2630     return 0;
2631 }
2632 
2633 // Sig pattern to identify AC: functions (Vx)
2634 // Function starts directly after its debug string
2635 int match_strsig102(firmware *fw, string_sig *sig, int j)
2636 {
2637     uint32_t sadr = idx2adr(fw,j);        // string address
2638     char *n = (char*)adr2ptr(fw,sadr);
2639     int nl = 0;
2640     if (n) {
2641         nl = strlen(n);
2642         nl = (((nl+3)>>2)<<2);
2643         if (nl > 0) {
2644             fwAddMatch(fw,sadr+nl,32,0,1102);
2645             return 1;
2646         }
2647     }
2648     return 0;
2649 }
2650 
2651 // Func is offset from a string, special case for GetDrive_FreeClusters
2652 //      Func            -   func
2653 //            ....
2654 //      string          -   DCB "str"
2655 int match_strsig103(firmware *fw, string_sig *sig, int j)
2656 {
2657     int ofst = vxworks_offset(fw, sig);
2658 
2659     int j1 = j+ofst;
2660     if (isSTMFD_LR(fw,j1))
2661     {
2662         // get third BL
2663         j1 = find_Nth_inst(fw,isBL,j1+1,20,3);
2664         if (j1<0)
2665             return 0;
2666         j1 = idxFollowBranch(fw,j1,0x01000001);
2667         // get first B
2668         j1 = find_Nth_inst(fw,isB,j1+1,32,1);
2669         if (j1<0)
2670             return 0;
2671         j1 = idxFollowBranch(fw,j1,0x01000001);
2672         fwAddMatch(fw,idx2adr(fw,j1),32,0,1103);
2673         return 1;
2674     }
2675     return 0;
2676 }
2677 
2678 // Sig pattern:
2679 //      Func            -   func
2680 //            .... [offset]
2681 //      Nth instruction backwards from string ref
2682 //      Ref to string   -       LDR Rx, pstr
2683 //            ....
2684 //      Ptr to string   -       DCD pstr
2685 // based on method 11
2686 // vxworks_offset to be encoded as: 0xQNPP
2687 // P) additional offset
2688 // Q) instruction to locate: 0 for STMFD_LR
2689 // N) search the instruction this many times - 1 (i.e. 0 = first instruction backwards)
2690 // prev instruction search range is limited by sig->offset
2691 // the reference to the string has to occur within 256 words (fixed range)
2692 int match_strsig104(firmware *fw, string_sig *sig, int j)
2693 {
2694     int ofst = vxworks_offset(fw, sig);
2695     int prinst = (ofst&0xf000)>>12;
2696     int ninst = ((ofst&0xf00)>>8)+1;
2697     ofst &= 0xff;
2698     void *instid;
2699     switch (prinst) {
2700         case 0:
2701         default:
2702             instid = (void*)isSTMFD_LR;
2703     }
2704 
2705     uint32_t sadr = idx2adr(fw,j);        // string address
2706     int j1;
2707     for (j1 = j+256; j1 >= 0; j1--)
2708     {
2709         if (isLDR(fw,j1))   // LDR ?
2710         {
2711             uint32_t pval = LDR2val(fw,j1);
2712             if (pval == sadr)
2713             {
2714                 int j2 = find_Nth_inst_rev(fw,instid,j1-1,sig->offset,ninst);
2715                 if (j2>0)
2716                 {
2717                     fwAddMatch(fw,idx2adr(fw,j2-ofst),32,0,1104);
2718                     return 1;
2719                 }
2720             }
2721         }
2722     }
2723 
2724     return 0;
2725 }
2726 
2727 // Call processing function based on type
2728 int find_strsig(firmware *fw, string_sig *sig)
2729 {
2730     switch (sig->type)
2731     {
2732     case 1:     return fw_string_process(fw, sig, match_strsig1, 1);
2733     case 2:     return fw_string_process_unaligned(fw, sig, match_strsig2);
2734     case 3:     return fw_string_process(fw, sig, match_strsig3, 1);
2735     case 4:     return fw_string_process(fw, sig, match_strsig4, 1);
2736     case 5:     return fw_string_process(fw, sig, match_strsig5, 1);
2737     case 6:     return fw_string_process(fw, sig, match_strsig6, 1);
2738     case 7:     return fw_string_process(fw, sig, match_strsig7, 1);
2739     case 8:     return find_strsig8(fw, sig);
2740     case 9:     return find_strsig9(fw, sig);
2741     case 11:    return fw_string_process(fw, sig, match_strsig11, 0);
2742     //case 12:    return find_strsig12(fw, sig);
2743     case 13:    return fw_string_process_unaligned(fw, sig, match_strsig13);
2744     case 15:    return fw_string_process(fw, sig, match_strsig15, 1);
2745     case 16:    return fw_process(fw, sig, match_strsig16);
2746     case 17:    return find_strsig17(fw, sig);
2747     case 19:    return find_strsig19(fw, sig);
2748     case 20:
2749         {
2750             int j = find_saved_sig(sig->ev_name);
2751             if (j >= 0)
2752             {
2753                 uint32_t fadr = followBranch2(fw,func_names[j].val,sig->offset);
2754                 fwAddMatch(fw,fadr,32,0,120);
2755                 return 1;
2756             }
2757             return 0;
2758         }
2759     case 21:    return fw_process(fw, sig, (int (*)(firmware*, string_sig*, int))(sig->ev_name));
2760     case 22:    return ((int (*)(firmware*))(sig->ev_name))(fw);
2761     case 100:   return fw_string_process(fw, sig, match_strsig100, 0);
2762     case 101:   return fw_string_process(fw, sig, match_strsig101, 0);
2763     case 102:   return fw_string_process(fw, sig, match_strsig102, 0);
2764     case 103:   return fw_string_process(fw, sig, match_strsig103, 0);
2765     case 104:   return fw_string_process(fw, sig, match_strsig104, 0);
2766     }
2767 
2768     return 0;
2769 }
2770 
2771 //------------------------------------------------------------------------------------------------------------
2772 
2773 // Matching functions
2774 
2775 // Search using new style matching only
2776 void find_str_sig_matches(firmware *fw, const char *curr_name)
2777 {
2778     int i;
2779 
2780     int found_ev = 0;
2781 
2782     count = 0;
2783 
2784     for (i = 0; string_sigs[i].ev_name != 0 && !found_ev; i++)
2785     {
2786         if (strcmp(curr_name, string_sigs[i].name) == 0)
2787         {
2788             if (find_strsig(fw, &string_sigs[i]))
2789             {
2790                 found_ev = 1;
2791                 break;
2792             }
2793         }
2794     }
2795 
2796     if (count > 1)
2797     {
2798         qsort(matches, count, sizeof(Match), (void*)match_compare);
2799     }
2800 
2801     if (count > 0)
2802     {
2803         save_sig(curr_name, matches->ptr);
2804     }
2805 }
2806 
2807 // Search using new style matching first
2808 // If not found used old style matching
2809 void find_matches(firmware *fw, const char *curr_name)
2810 {
2811     FuncSig *sig, *s;
2812     BufRange *n;
2813     uint32_t *p;
2814     int i, j;
2815     int fail, success;
2816 
2817     int found_ev = 0;
2818 
2819     count = 0;
2820 
2821     // Already found (eventproc)?
2822     i = find_saved_sig(curr_name);
2823     if (i >= 0)
2824     {
2825         if ((func_names[i].val != 0) && (func_names[i].flags & EV_MATCH) != 0)
2826         {
2827             fwAddMatch(fw,func_names[i].val,32,0,120);
2828             found_ev = 1;
2829         }
2830     }
2831 
2832 
2833     // Try and match using 'string' based signature matching first
2834     for (i = 0; string_sigs[i].ev_name != 0 && !found_ev; i++)
2835     {
2836         if (strcmp(curr_name, string_sigs[i].name) == 0)
2837         {
2838             if (find_strsig(fw, &string_sigs[i]))
2839             {
2840                 found_ev = 1;
2841                 break;
2842             }
2843         }
2844     }
2845 
2846     // If not found see if the name is in the old style instruction compare match table
2847     // Set start value for j in next section if found
2848     if (!found_ev)
2849     {
2850         found_ev = 1;
2851         for (j=0; func_list[j].name; j++)
2852         {
2853             if (strcmp(curr_name,func_list[j].name) == 0)
2854             {
2855                 found_ev = 0;
2856                 break;
2857             }
2858         }
2859     }
2860 
2861     // Not found so far, try instruction comparison matching
2862     while (!found_ev)
2863     {
2864         sig = func_list[j].sig;
2865 
2866         for (n = fw->br; n != 0; n = n->next)
2867         {
2868             for (p = n->p, i = 0; i < n->len; p++, i++)
2869             {
2870                 fail = 0;
2871                 success = 0;
2872                 for (s = sig; s->offs != -1; s++)
2873                 {
2874                     if ((p[s->offs] & s->mask) != s->value)
2875                         fail++;
2876                     else
2877                         success++;
2878                 }
2879                 // If sig starts with STMFD and first instruction does not match ignore it
2880                 if (((p[sig->offs] & sig->mask) != sig->value) && (sig->offs == 0) && (sig->value == 0xe92d0000)) success = 0;
2881                 if (success > fail)
2882                 {
2883                     if (s->mask == -2)
2884                     {
2885                         int end_branch = 0;
2886                         int idx = 0;
2887                         uint32_t *p1 = 0;
2888                         if ((fw->buf[n->off+i+s->value] & 0x0F000000) == 0x0A000000)   // B
2889                         {
2890                             idx = adr2idx(fw, followBranch2(fw, idx2adr(fw,n->off+i+s->value), 0xF0000001));
2891                             if ((idx >= 0) && (idx < fw->size))
2892                             {
2893                                 end_branch = 1;
2894                                 p1 = &fw->buf[idx];
2895                             }
2896                         }
2897                         int fail2 = 0;
2898                         int success2 = 0;
2899                         //fprintf(stderr,"\t%s %d %08x %08x %d %d\n",curr_name,idx,idx2adr(fw,idx),idx2adr(fw,i+n->off),success,fail);
2900                         s++;
2901                         for (; s->offs != -1; s++)
2902                         {
2903                             if (!end_branch || (p1[s->offs] & s->mask) != s->value){
2904                                 fail2++;
2905                             } else {
2906                                 success2++;
2907                             }
2908                         }
2909                         if (fail2 == 0)
2910                         {
2911                             success = success + fail + success2;
2912                             fail = 0;
2913                         }
2914                         else
2915                         {
2916                             success = success + success2;
2917                             fail = fail + fail2;
2918                         }
2919                         //fprintf(stderr,"\t%s %d %08x %08x %d %d\n",curr_name,idx,idx2adr(fw,idx),idx2adr(fw,i+n->off),success,fail);
2920                     }
2921                 }
2922                 if (success > fail)
2923                 {
2924                     // Special case for drive space functions, see if there is a refernce to "Mounter.c" in the function
2925                     // Increase match % if so, increase fail count if not
2926                     if ((strcmp(curr_name, "GetDrive_ClusterSize") == 0) ||
2927                         (strcmp(curr_name, "GetDrive_FreeClusters") == 0) ||
2928                         (strcmp(curr_name, "GetDrive_TotalClusters") == 0))
2929                     {
2930                         int fnd = 0;
2931                         for (s = sig; s->offs != -1; s++)
2932                         {
2933                             if (isLDR_PC_cond(fw,n->off+i+s->offs))
2934                             {
2935                                 int m = adr2idx(fw,LDR2val(fw,n->off+i+s->offs));
2936                                 if ((m >= 0) && (m < fw->size) && (strcmp((char*)(&fw->buf[m]),"Mounter.c") == 0))
2937                                 {
2938                                     fnd = 1;
2939                                 }
2940                             }
2941                             else if (isADR_PC_cond(fw,n->off+i+s->offs))
2942                             {
2943                                 int m = adr2idx(fw,ADR2adr(fw,n->off+i+s->offs));
2944                                 if ((m >= 0) && (m < fw->size) && (strcmp((char*)(&fw->buf[m]),"Mounter.c") == 0))
2945                                 {
2946                                     fnd = 1;
2947                                 }
2948                             }
2949                         }
2950                         if (fnd)
2951                             success++;
2952                         else
2953                             fail++;
2954                     }
2955                     fwAddMatch(fw,idx2adr(fw,i+n->off),success,fail,func_list[j].ver);
2956                     if (count >= MAX_MATCHES)
2957                     {
2958                         bprintf("// WARNING: too many matches for %s!\n", func_list[j].name);
2959                         break;
2960                     }
2961                 }
2962             }
2963         }
2964 
2965         // same name, so we have another version of the same function
2966         if ((func_list[j+1].name == NULL) || (strcmp(curr_name, func_list[j+1].name) != 0))
2967         {
2968             found_ev = 1;
2969             break;
2970         }
2971         j++;
2972     }
2973 
2974     if (count > 1)
2975     {
2976         qsort(matches, count, sizeof(Match), (void*)match_compare);
2977     }
2978 
2979     if (count > 0)
2980     {
2981         save_sig(curr_name, matches->ptr);
2982     }
2983 }
2984 
2985 // Output match results for function
2986 void print_results(firmware *fw, const char *curr_name, int k)
2987 {
2988     int i;
2989     int err = 0;
2990     char line[500] = "";
2991 
2992     if (func_names[k].flags & DONT_EXPORT) return;
2993 
2994     // find best match and report results
2995     osig* ostub2 = find_sig(fw->sv->stubs,curr_name);
2996 
2997     if ((count == 0)
2998         || (matches->fail > 0)
2999         || (ostub2 && (matches->ptr != ostub2->val))
3000        )
3001     {
3002         if (!ostub2 || (ostub2->type != TYPE_IGNORE))
3003             err = 1;
3004         func_names[k].flags |= BAD_MATCH;
3005     }
3006     else
3007     {
3008         if (func_names[k].flags & UNUSED) return;
3009     }
3010 
3011     // write to header (if error) or body buffer (no error)
3012     out_hdr = err;
3013 
3014     char *macro = "NHSTUB";
3015     if (strncmp(curr_name,"task_",5) == 0 ||
3016         strncmp(curr_name,"hook_",5) == 0) macro = "   DEF";
3017 
3018     if (count == 0)
3019     {
3020         if (func_names[k].flags & OPTIONAL) return;
3021         char fmt[51] = "";
3022         sprintf(fmt, "// ERROR: %%s is not found. %%%ds//--- --- ", (int)(34-strlen(curr_name)));
3023         sprintf(line+strlen(line), fmt, curr_name, "");
3024     }
3025     else
3026     {
3027         if (ostub2 || (func_names[k].flags & UNUSED))
3028             sprintf(line+strlen(line),"//%s(%-37s,0x%08x) //%3d ", macro, curr_name, matches->ptr, matches->sig);
3029         else
3030             sprintf(line+strlen(line),"%s(%-39s,0x%08x) //%3d ", macro, curr_name, matches->ptr, matches->sig);
3031 
3032         if (matches->fail > 0)
3033             sprintf(line+strlen(line),"%2d%% ", matches->success*100/(matches->success+matches->fail));
3034         else
3035             sprintf(line+strlen(line),"    ");
3036     }
3037 
3038     if (ostub2)
3039     {
3040         if (ostub2->type == TYPE_IGNORE)
3041             sprintf(line+strlen(line),"       Overridden");
3042         else if ((count > 0) && (matches->ptr == ostub2->val))
3043             sprintf(line+strlen(line),"       == 0x%08x    ",ostub2->val);
3044         else
3045             sprintf(line+strlen(line),"   *** != 0x%08x    ",ostub2->val);
3046     }
3047     else
3048         sprintf(line+strlen(line),"                        ");
3049 
3050     for (i=strlen(line)-1; i>=0 && line[i]==' '; i--) line[i] = 0;
3051     bprintf("%s\n",line);
3052 
3053     for (i=1;i<count && matches[i].fail==matches[0].fail;i++)
3054     {
3055         if (matches[i].ptr != matches->ptr)
3056         {
3057             bprintf("// ALT: %s(%s, 0x%x) // %d %d/%d\n", macro, curr_name, matches[i].ptr, matches[i].sig, matches[i].success, matches[i].fail);
3058         }
3059     }
3060 }
3061 
3062 //------------------------------------------------------------------------------------------------------------
3063 
3064 typedef struct
3065 {
3066     uint16_t mode;
3067     char *nm;
3068 } ModeMapName;
3069 
3070 ModeMapName mmnames[] = {
3071     { 32768,"MODE_AUTO" },
3072     { 32769,"MODE_M" },
3073     { 32770,"MODE_AV" },
3074     { 32771,"MODE_TV" },
3075     { 32772,"MODE_P" },
3076 
3077     { 65535,"" }
3078 };
3079 
3080 char* mode_name(uint16_t v)
3081 {
3082     int i;
3083     for (i=0; mmnames[i].mode != 65535; i++)
3084     {
3085         if (mmnames[i].mode == v)
3086             return mmnames[i].nm;
3087     }
3088 
3089     return "";
3090 }
3091 
3092 void output_modemap(firmware *fw, int k, int l)
3093 {
3094     int cnt = 0;
3095 
3096     bprintf("%08x\n",idx2adr(fw,k));
3097     // detect table member size
3098     if (fw->buf[k] & 0xffff0000)
3099     {
3100         // 16bit entries
3101         uint16_t *p = (uint16_t*)(&fw->buf[k]);
3102         k = 0;
3103         while ((*p != 0xFFFF) && (k < l*2))
3104         {
3105             osig *m = find_sig_val(fw->sv->modemap, *p);
3106             if (!m)
3107             {
3108                 char *s = mode_name(*p);
3109                 bprintf("// Mode %5d in firmware but not in current modemap",*p);
3110                 if (strcmp(s,"") != 0)
3111                     bprintf(" (%s)",s);
3112                 bprintf("\n");
3113                 cnt++;
3114             }
3115             else
3116             {
3117                 m->pct = 100;
3118             }
3119             p++;
3120             k++;
3121         }
3122     }
3123     else
3124     {
3125         // 32bit entries (first one is 0)
3126         uint32_t *p = (uint32_t*)(&fw->buf[k]);
3127         k = 0;
3128         while (k < l)
3129         {
3130             osig *m = find_sig_val(fw->sv->modemap, *p);
3131             if (!m)
3132             {
3133                 osig *m = find_sig_val(fw->sv->modemap, (*p)&0xffff);
3134                 if (!m)
3135                 {
3136                     char *s = mode_name(*p);
3137                     if ((*p)&0xffff0000)
3138                         bprintf("// Strange mode 0x%08x in firmware but not in current modemap",*p);
3139                     else
3140                         bprintf("// Mode %d in firmware but not in current modemap",*p);
3141                     if (strcmp(s,"") != 0)
3142                         bprintf(" (%s)",s);
3143                     bprintf("\n");
3144                 }
3145                 else
3146                 {
3147                     char *s = mode_name((*p)&0xffff);
3148                     if ((*p)&0xffff0000)
3149                         bprintf("// Strange mode 0x%08x in firmware, found in modemap as %d (%s)",*p,m->val,m->nm);
3150                     else
3151                         bprintf("// Mode %d in firmware, found in modemap as %d (%s)",*p,m->val,m->nm); // impossible?
3152                     if (strcmp(s,"") != 0)
3153                         bprintf(" (%s)",s);
3154                     bprintf("\n");
3155                     m->pct = 100;
3156                 }
3157                 cnt++;
3158             }
3159             else
3160             {
3161                 m->pct = 100;
3162             }
3163             p++;
3164             k++;
3165         }
3166     }
3167     osig *m = fw->sv->modemap;
3168     while (m)
3169     {
3170         if (m->pct != 100)    // not matched above?
3171         {
3172             bprintf("// Current modemap entry not found in firmware - %-24s %5d\n",m->nm,m->val);
3173             cnt++;
3174         }
3175         m = m->nxt;
3176     }
3177     if (cnt == 0)
3178     {
3179         bprintf("// No problems found with modemap table.\n");
3180     }
3181 }
3182 
3183 int find_modelist(firmware *fw, uint32_t fadr)
3184 {
3185     uint32_t j1;
3186     int k1, k2;
3187     // flashparamstable 1st entry
3188     j1 = fwval(fw,adr2idx(fw,fadr));
3189     k1 = adr2idx(fw,j1);
3190     if (k1<0)
3191         return 0;
3192     k2 = find_inst_rev(fw,isLDMFD_PC,k1-1,50);
3193     if (k2<0)
3194     {
3195         // newest vx models
3196         k2 = find_Nth_inst_rev(fw,isMOV,k1-1,16,2);
3197     }
3198     if (k2<0)
3199         return 0;
3200     k1 = find_inst_rev(fw,isLDR,k2,5);
3201     if (k1<0)
3202         return 0;
3203     j1 = LDR2val(fw,k1);
3204     k1 = adr2idx(fw,j1);
3205     if (k1<0)
3206         return 0;
3207     j1 = fwval(fw,k1);
3208     k1 = adr2idx(fw,j1);
3209     if (k1<0)
3210         return 0;
3211     k1 = find_inst_rev(fw,isMOV,k1-1,120);
3212     if (k1<0)
3213         return 0;
3214     if (fwval(fw,k1) != 0xe1a0f00e) // mov pc, lr
3215         return 0;
3216     k1--;
3217     if (!(isLDR(fw,k1) && (fwRd(fw,k1)==0))) // ldr r0,
3218         return 0;
3219     k2 = k1;
3220     j1 = LDR2val(fw,k1);
3221     k1 = adr2idx(fw,j1);
3222     if (k1<0)
3223         return 0;
3224     
3225     bprintf("// Firmware modemap table found @%08x -> ",idx2adr(fw,k1));
3226     output_modemap(fw,k1,k2-k1);
3227     return 1;
3228 
3229 }
3230 
3231 static uint32_t FlashParamsTable_address = 0;
3232 
3233 int match_FlashParamsTable2(firmware *fw, int k, uint32_t v1, uint32_t v2)
3234 {
3235     if (fw->buf[k] == v1)
3236     {
3237         FlashParamsTable_address = idx2adr(fw,k);
3238         return 1;
3239     }
3240     return 0;
3241 }
3242 
3243 int match_FlashParamsTable(firmware *fw, int k, uint32_t v1, uint32_t v2)
3244 {
3245     if ((fw->buf[k] > fw->base) && (fw->buf[k+1] == 0x00010000) && ((fw->buf[k+2] == 0xFFFF0000)||(fw->buf[k+2] == 0xFFFF0002)))
3246     {
3247         if (search_fw(fw, match_FlashParamsTable2, idx2adr(fw,k), 0, 1))
3248             return 1;
3249     }
3250     // ixus30, 40
3251     if ((fw->buf[k+1] > fw->base) && (fw->buf[k] == 0x00000000) && (fw->buf[k+2] == 0x00000001) &&
3252         (fw->buf[k+3] == 0x00000000) && (fw->buf[k+4] == 0xffffffff))
3253     {
3254         if (search_fw(fw, match_FlashParamsTable2, idx2adr(fw,k), 0, 1))
3255             return 1;
3256     }
3257     return 0;
3258 }
3259 
3260 void find_modemap(firmware *fw)
3261 {
3262     out_hdr = 1;
3263 
3264     // Find 'FlashParamsTable'
3265     search_fw(fw, match_FlashParamsTable, 0, 0, 1);
3266     // Find 'modelist'
3267     // get flashparamstable 1st entry -> jump to that address -> search backwards 1st ldmfd_pc (mov pc,lr in newest vx) ->
3268     // search backwards ldr address -> jump to that address (this is the propertytable, not researched) ->
3269     // get 1st entry -> jump to that address -> search backwards 1st mov pc,lr ->
3270     // get modemaptable address from the prev ldr
3271     // old vx mode entries are 32 bit, all newer cameras have 16 bit entries
3272     if (FlashParamsTable_address != 0)
3273     {
3274         add_blankline();
3275         bprintf("// Check of modemap from 'platform/CAMERA/shooting.c':\n");
3276         find_modelist(fw,FlashParamsTable_address);
3277     }
3278 }
3279 
3280 //------------------------------------------------------------------------------------------------------------
3281 
3282 int find_FileAccessSem(firmware *fw)
3283 {
3284     void print_stubs_min(firmware *fw, const char *name, uint32_t fadr, uint32_t atadr);
3285     int s1 = find_str(fw, "FileSem.c");
3286     if (s1 < 0)
3287         return 0;
3288     s1 = find_inst(fw, isLDR_PC, s1+2, 16);
3289     if (s1 < 0)
3290         return 0;
3291     uint32_t u1 = LDR2val(fw, s1);
3292     if (u1 > fw->memisostart)
3293         return 0;
3294     print_stubs_min(fw,"fileio_semaphore",u1,idx2adr(fw,s1));
3295     return 1;
3296 }
3297 
3298 //------------------------------------------------------------------------------------------------------------
3299 
3300 int find_DebugAssert_argcount(firmware *fw)
3301 {
3302     int s1 = find_str_ref(fw, "Memory.c");
3303     if (s1 < 0)
3304         return 0;
3305     int k = isLDR_PC(fw, s1);
3306     if (!k)
3307         return 0;
3308     k = fwRd(fw, s1);
3309     if (k > 0)
3310         bprintf("//#define CAM_3ARG_DebugAssert 1\n");
3311     return 1;
3312 }
3313 
3314 /*
3315 int match_CAM_UNCACHED_BIT(firmware *fw, int k, int v)
3316 {
3317     if ((fw->buf[k] & 0x0FFFF000) == 0x03C00000)    // BIC
3318     {
3319         uint32_t fadr = ALUop2(fw,k);
3320         bprintf("//#undef  CAM_UNCACHED_BIT\n");
3321         bprintf("//#define CAM_UNCACHED_BIT  0x%08x // Found @0x%08x\n",fadr,idx2adr(fw,k));
3322     }
3323 
3324     return 0;
3325 }
3326 */
3327 
3328 // Search for things that go in 'platform_camera.h'
3329 void find_platform_vals(firmware *fw)
3330 {
3331     int k,k1;
3332 
3333     out_hdr = 1;
3334     add_blankline();
3335 
3336     bprintf("// Values below go in 'platform_camera.h':\n");
3337 
3338 /*
3339     bprintf("//#define CAM_DRYOS         1\n");
3340     if (fw->dryos_ver >= 39)
3341         bprintf("//#define CAM_DRYOS_2_3_R39 1 // Defined for cameras with DryOS version R39 or higher\n");
3342     if (fw->dryos_ver >= 47)
3343         bprintf("//#define CAM_DRYOS_2_3_R47 1 // Defined for cameras with DryOS version R47 or higher\n");
3344 
3345     // Find 'RAW' image size
3346     uint32_t raw_width = 0;
3347     uint32_t raw_height = 0;
3348     uint32_t kw=0, kh=0;
3349 
3350     k = find_str_ref(fw, "\r[%ld] AdjDrvType[%02ld] -> DrvType[%02");
3351     if (k >= 0)
3352     {
3353         // Width
3354         for (k1 = k-1; k1 >= k-20; k1--)
3355         {
3356             if ((fw->buf[k1] & 0x0FFF0FFF) == 0x058D0034)           // STRxx Rn, [SP,#0x34]
3357             {
3358                 if ((fw->buf[k1-1] & 0x0FFF0000) == 0x03A00000)     // MOVxx Rn, #YYY
3359                 {
3360                     raw_width = ALUop2(fw, k1-1);
3361                     kw = k1-1;
3362                 }
3363                 else if ((fw->buf[k1-2] & 0x0FFF0000) == 0x03A00000)// MOVxx Rn, #YYY
3364                 {
3365                     raw_width = ALUop2(fw, k1-2);
3366                     kw = k1-2;
3367                 }
3368                 else if (isLDR_PC_cond(fw,k1-1))
3369                 {
3370                     raw_width = LDR2val(fw,k1-1);
3371                     kw = k1-1;
3372                 }
3373                 else if (isLDR_PC_cond(fw,k1-2))
3374                 {
3375                     raw_width = LDR2val(fw,k1-2);
3376                     kw = k1-2;
3377                 }
3378             }
3379         }
3380         // Height
3381         for (k1 = k-1; k1 >= k-20; k1--)
3382         {
3383             if ((fw->buf[k1] & 0x0FFF0FFF) == 0x058D0030)           // STRxx Rn, [SP,#0x30]
3384             {
3385                 if ((fw->buf[k1-1] & 0x0FFF0000) == 0x03A00000)     // MOVxx Rn, #YYY
3386                 {
3387                     raw_height = ALUop2(fw, k1-1);
3388                     kh = k1-1;
3389                 }
3390                 else if ((fw->buf[k1-2] & 0x0FFF0000) == 0x03A00000)// MOVxx Rn, #YYY
3391                 {
3392                     raw_height = ALUop2(fw, k1-2);
3393                     kh = k1-2;
3394                 }
3395                 else if (isLDR_PC_cond(fw,k1-1))
3396                 {
3397                     raw_height = LDR2val(fw,k1-1);
3398                     kh = k1-1;
3399                 }
3400                 else if (isLDR_PC_cond(fw,k1-2))
3401                 {
3402                     raw_height = LDR2val(fw,k1-2);
3403                     kh = k1-2;
3404                 }
3405                 if ((fw->buf[k1-1] & 0x0FFF0000) == 0x02400000)     // SUBxx Rn, #YYY
3406                 {
3407                     raw_height = raw_width - ALUop2(fw, k1-1);
3408                     kh = k1-1;
3409                 }
3410             }
3411         }
3412     }
3413 
3414     if ((raw_width == 0) && (raw_height == 0))
3415     {
3416         k = find_str_ref(fw, " CrwAddress %lx, CrwSize H %ld V %ld\r");
3417         if (k >= 0)
3418         {
3419             // Width
3420             for (k1=k-1; k1>=k-5; k1--)
3421             {
3422                 if ((fw->buf[k1] & 0xFFFFF000) == 0xE3A02000)       // MOV R2, #nnn
3423                 {
3424                     raw_width = ALUop2(fw,k1);
3425                     kw = k1;
3426                 }
3427                 else
3428                 if (isLDR_PC(fw,k1) && ((fw->buf[k1]& 0x0000F000) == 0x00002000))   // LDR R2, =nnn
3429                 {
3430                     raw_width = LDR2val(fw,k1);
3431                     kw = k1;
3432                 }
3433             }
3434             // Height
3435             for (k1=k-1; k1>=k-5; k1--)
3436             {
3437                 if ((fw->buf[k1] & 0xFFFFF000) == 0xE3A03000)       // MOV R3, #nnn
3438                 {
3439                     raw_height = ALUop2(fw,k1);
3440                     kh = k1;
3441                 }
3442                 else
3443                 if (isLDR_PC(fw,k1) && ((fw->buf[k1]& 0x0000F000) == 0x00003000))   // LDR R3, =nnn
3444                 {
3445                     raw_height = LDR2val(fw,k1);
3446                     kh = k1;
3447                 }
3448                 else
3449                 if ((fw->buf[k1] & 0xFFFFF000) == 0xE2423000)       // SUB R3, R2, #nnn
3450                 {
3451                     raw_height = raw_width - ALUop2(fw,k1);
3452                     kh = k1;
3453                 }
3454             }
3455         }
3456     }
3457 
3458     if (raw_width != 0)
3459     {
3460         bprintf("//#define CAM_RAW_ROWPIX    %d // Found @0x%08x\n",raw_width,idx2adr(fw,kw));
3461     }
3462     else
3463     {
3464         bprintf("//#define CAM_RAW_ROWPIX    *** Not Found ***\n");
3465     }
3466     if (raw_height != 0)
3467     {
3468         bprintf("//#define CAM_RAW_ROWS      %d // Found @0x%08x\n",raw_height,idx2adr(fw,kh));
3469     }
3470     else
3471     {
3472         bprintf("//#define CAM_RAW_ROWS      *** Not Found ***\n");
3473     }
3474 
3475     // Find 'CAM_UNCACHED_BIT'
3476     search_saved_sig(fw, "FreeUncacheableMemory", match_CAM_UNCACHED_BIT, 0, 0, 8);
3477 */
3478 
3479     // Find 'PARAM_CAMERA_NAME'
3480     if (FlashParamsTable_address != 0)
3481     {
3482         k1 = adr2idx(fw,FlashParamsTable_address);
3483         for (k=k1; k<k1+20; k++)
3484         {
3485             uint32_t fadr = fwval(fw,k);
3486             int k2 = adr2idx(fw,fadr);
3487             if (idx_valid(fw,k2))
3488             {
3489                 uint32_t sadr = fwval(fw,k2);
3490                 k2 = adr2idx(fw,sadr);
3491                 if (idx_valid(fw,k2))
3492                 {
3493                     char *s = adr2ptr(fw,sadr);
3494                     if (((fw->cam != 0) && (strcmp(s,fw->cam) == 0)) || (strcmp(s,"Unknown") == 0))
3495                     {
3496                         bprintf("//#define PARAM_CAMERA_NAME %d // Found @0x%08x\n",k-k1,fadr);
3497                         break;
3498                     }
3499                 }
3500             }
3501         }
3502     }
3503 
3504     find_DebugAssert_argcount(fw);
3505 }
3506 
3507 //------------------------------------------------------------------------------------------------------------
3508 
3509 uint32_t find_viewport_address(firmware *fw, int *kout)
3510 {
3511     int k, k1;
3512 
3513     // find viewwport address for 'vid_get_viewport_fb'
3514     k = find_str_ref(fw, "VRAM Address  : %p\r");
3515     if (k >= 0)
3516     {
3517         for (k1=k-1; k1>k-8; k1--)
3518         {
3519             if (isLDR(fw,k1) && isLDR(fw,k1+1))
3520             {
3521                 uint32_t v1 = LDR2val(fw,k1);
3522                 uint32_t v2 = LDR2val(fw,k1+1);
3523                 if (v2 > v1) v1 = v2;
3524                 *kout = k1;
3525                 return v1;
3526             }
3527         }
3528     }
3529 
3530     *kout = -1;
3531     return 0;
3532 }
3533 
3534 int match_vid_get_bitmap_fb(firmware *fw, int k, int v)
3535 {
3536     if (isBL(fw,k-1) && // BL
3537         isLDR_PC(fw,k))
3538     {
3539         uint32_t v1 = LDR2val(fw,k);
3540         bprintf("//void *vid_get_bitmap_fb()        { return (void*)0x%08x; }             // Found @0x%08x\n",v1,idx2adr(fw,k));
3541         return 1;
3542     }
3543     else
3544     if (isBL(fw,k-1) && // BL
3545         (isLDR_PC(fw,k+1)))
3546     {
3547         uint32_t v1 = LDR2val(fw,k+1);
3548         bprintf("//void *vid_get_bitmap_fb()        { return (void*)0x%08x; }             // Found @0x%08x\n",v1,idx2adr(fw,k));
3549         return 1;
3550     }
3551 
3552     return 0;
3553 }
3554 
3555 int match_get_flash_params_count(firmware *fw, int k, int v)
3556 {
3557     if ((fw->buf[k] & 0xFFF00FFF) == 0xE3C00901)    // BIC Rn, Rn, #0x4000
3558     {
3559         uint32_t r = (fw->buf[k] & 0x0000F000)<<4;       // Register
3560         int n;
3561         for (n=k+1; n<k+20; n++)
3562         {
3563             if (((fw->buf[n] & 0xFFF00000) == 0xE3500000) && ((fw->buf[n] & 0x000F0000) == r))  // CMP, Rn #val
3564             {
3565                 // the found value needs to be increased by one (BLS instruction follows)
3566                 bprintf("//int get_flash_params_count(void) { return 0x%02x; }                          // Found @0x%08x\n",(fw->buf[n]&0xFFF)+1,idx2adr(fw,n));
3567                 return 1;
3568             }
3569         }
3570     }
3571 
3572     return 0;
3573 }
3574 
3575 // based on match_get_flash_params_count
3576 int match_uiprop_count(firmware *fw, int k, int v)
3577 {
3578     uint32_t uic = 0;
3579     int j = -1;
3580     if (isB(fw, k+6))
3581     {
3582         j = idxFollowBranch(fw,k+6,0x01000001);
3583     }
3584     if (j > 0)
3585     {
3586         int m;
3587         for (m=j; m<j+32; m++)
3588         {
3589             if (isLDMFD_PC(fw,m)) break;
3590             if (isCMP(fw,m))
3591             {
3592                 uint32_t v1 = ALUop2(fw,m);
3593                 if ((v1 > 0x10)&&(v1 < 0xa0))
3594                 {
3595                     uic = v1+1; // BLS follows this CMP instruction
3596                     j = m;
3597                     break;
3598                 }
3599             }
3600         }
3601     }
3602 
3603     if (uic == 0) return 0;
3604 
3605     char *name = "uiprop_count";
3606     osig *o = find_sig(fw->sv->stubs_min,name);
3607     if (o)
3608     {
3609         bprintf("//DEF_CONST(%-34s,0x%08x) // Found @0x%08x",name,uic,idx2adr(fw,j));
3610         if (uic != o->val)
3611         {
3612             bprintf(", ** != ** stubs_min = 0x%08x (%s)",o->val,o->sval);
3613         }
3614         else
3615         {
3616             bprintf(",          stubs_min = 0x%08x (%s)",o->val,o->sval);
3617         }
3618     }
3619     else
3620     {
3621         bprintf("DEF_CONST(%-34s,0x%08x) // Found @0x%08x",name,uic,idx2adr(fw,j));
3622     }
3623     bprintf("\n");
3624     return 1;
3625 }
3626 
3627 int isMOVLRPC(firmware *fw, int offset)
3628 {
3629     return (fwval(fw,offset) == 0xE1A0E00F); // MOV LR, PC
3630 }
3631 
3632 int match_imager_active(firmware *fw, int k, int v)
3633 {
3634     int gotit = 0;
3635     int reg = -1;
3636     int o = 0;
3637     uint32_t adr,where;
3638     if (fwval(fw,k) == 0xe49df004) // POP {PC}
3639     {
3640         int k1 = find_inst_rev(fw, isBL, k-1, 10);
3641         if (k1 == -1)
3642             return 0;
3643         uint32_t a;
3644         int k2 = k1 - 8;
3645         for (k1=k1-1;k1>=k2;k1--)
3646         {
3647             if (isLDR(fw,k1) || isADR(fw,k1))
3648             {
3649                 if (isADR(fw,k1))
3650                 {
3651                     a = ADR2adr(fw, k1);
3652                 }
3653                 else
3654                 {
3655                     a = LDR2val(fw, k1);
3656                 }
3657                 if ((a>fw->base) && ((a&3) == 0))
3658                 {
3659                     int k3 = adr2idx(fw, a);
3660                     if (isSTMFD_LR(fw,k3))
3661                     {
3662                         k3 = find_inst(fw, isMOVLRPC, k3+1, 6);
3663                         if (k3 != -1)
3664                         {
3665                             int k4;
3666                             for(k4=5; k4>0; k4--)
3667                             {
3668                                 if (isSTR_cond(fw,k3+k4))
3669                                 {
3670                                     reg = fwRn(fw,k3+k4);
3671                                     o = fwval(fw,k3+k4) & 0xff; // offset, should be around 4
3672                                     where = idx2adr(fw,k3+k4);
3673                                 }
3674                                 if (reg>=0 && isLDR_cond(fw,k3+k4) && fwRd(fw,k3+k4)==reg)
3675                                 {
3676                                     adr = LDR2val(fw,k3+k4);
3677                                     if (adr < fw->memisostart)
3678                                     {
3679                                         gotit = 1;
3680                                         break;
3681                                     }
3682                                 }
3683                             }
3684                             if (gotit)
3685                                 break;
3686                         }
3687                     }
3688                 }
3689             }
3690         }
3691     }
3692     if (gotit)
3693     {
3694         bprintf("DEF(%-40s,0x%08x) // Found @0x%08x (0x%x + %i)\n","imager_active",adr+o,where,adr,o);
3695         return 1;
3696     }
3697     return 0;
3698 }
3699 
3700 // Search for things that go in 'lib.c'
3701 void find_lib_vals(firmware *fw)
3702 {
3703     //int k,k1;
3704 
3705     out_hdr = 1;
3706     add_blankline();
3707 
3708     bprintf("// Values below go in 'lib.c':\n");
3709 /*
3710     // Find 'vid_get_bitmap_fb'
3711     search_saved_sig(fw, "DispCon_ShowBitmapColorBar", match_vid_get_bitmap_fb, 0, 1, 30);
3712 
3713     // find 'vid_get_viewport_fb'
3714     uint32_t v = find_viewport_address(fw,&k);
3715     if (k >= 0)
3716     {
3717         bprintf("//void *vid_get_viewport_fb()      { return (void*)0x%08x; }             // Found @0x%08x\n",v,idx2adr(fw,k));
3718     }
3719 
3720     // find 'vid_get_viewport_fb_d'
3721     static int fbd[3][3] =
3722     {
3723         { -2, -3,  1 },
3724         {  1,  3,  4 },
3725         { -1, -2,  1 },
3726     };
3727     int sadr = find_str(fw, "ImagePlayer.c");
3728     k = find_nxt_str_ref(fw, sadr, -1);
3729     int found = 0;
3730     while ((k >= 0) && !found)
3731     {
3732         int f;
3733         for (f=0; f<3 && !found; f++)
3734         {
3735             if (isLDR(fw,k+fbd[f][0]) && isLDR(fw,k+fbd[f][1]) && isLDR(fw,k+fbd[f][2]))
3736             {
3737                 int reg = fw->buf[k+fbd[f][2]] & 0x000F0000;    // Index register used
3738                 int ka = 0;
3739                 if (((fw->buf[k+fbd[f][0]] & 0x0000F000) << 4) == reg)      { ka = k+fbd[f][0]; }
3740                 else if (((fw->buf[k+fbd[f][1]] & 0x0000F000) << 4) == reg) { ka = k+fbd[f][1]; }
3741                 if (ka > 0)
3742                 {
3743                     uint32_t adr = LDR2val(fw,ka);
3744                     for (k1=k+2; k1<k+20; k1++)
3745                     {
3746                         if (isSTR(fw,k1) && ((fw->buf[k1] & 0x000F0000) == reg))
3747                         {
3748                             uint32_t ofst = fw->buf[k1] & 0x00000FFF;
3749                             bprintf("DEF(%-40s,0x%08x) // Found 0x%04x (@0x%08x) + 0x%02x (@0x%08x)\n","viewport_fb_d",adr+ofst,adr,idx2adr(fw,ka),ofst,idx2adr(fw,k1));
3750                             bprintf("//void *vid_get_viewport_fb_d()    { return (void*)(*(int*)(0x%04x+0x%02x)); } // Found @0x%08x & 0x%08x\n",adr,ofst,idx2adr(fw,ka),idx2adr(fw,k1));
3751                             found = 1;
3752                             break;
3753                         }
3754                     }
3755                 }
3756             }
3757         }
3758         k = find_nxt_str_ref(fw, sadr, k);
3759     }
3760 
3761     // find 'camera_jpeg_count_str'
3762     k = find_str_ref(fw, "9999");
3763     if (k >= 0)
3764     {
3765         if (isLDR(fw,k-1) && isBL(fw,k+1))
3766         {
3767             uint32_t v1 = LDR2val(fw,k-1);
3768             bprintf("DEF(%-40s,0x%08x) // Found @0x%08x\n","jpeg_count_str",v1,idx2adr(fw,k-1));
3769             bprintf("//char *camera_jpeg_count_str()    { return (char*)0x%08x; }             // Found @0x%08x\n",v1,idx2adr(fw,k-1));
3770         }
3771     }
3772 
3773     // find 'hook_raw_size'
3774     k = find_str_ref(fw, "CRAW BUFF SIZE  %p");
3775     if (k >= 0)
3776     {
3777         if (isLDR(fw,k-1))
3778         {
3779             uint32_t craw_bufsize = LDR2val(fw,k-1);
3780             bprintf("//long hook_raw_size()             { return 0x%08x; }                    // Found @0x%08x\n",craw_bufsize,idx2adr(fw,k-1));
3781         }
3782     }
3783 */
3784     // Find value for 'get_flash_params_count'
3785     search_saved_sig(fw, "GetParameterData", match_get_flash_params_count, 0, 0, 30);
3786 }
3787 
3788 //------------------------------------------------------------------------------------------------------------
3789 
3790 void print_stubs_min(firmware *fw, const char *name, uint32_t fadr, uint32_t atadr)
3791 {
3792     osig *o = find_sig(fw->sv->stubs_min,name);
3793     if (o)
3794     {
3795         bprintf("//DEF(%-40s,0x%08x) // Found @0x%08x",name,fadr,atadr);
3796         if (fadr != o->val)
3797         {
3798             bprintf(", ** != ** stubs_min = 0x%08x (%s)",o->val,o->sval);
3799         }
3800         else
3801         {
3802             bprintf(",          stubs_min = 0x%08x (%s)",o->val,o->sval);
3803         }
3804     }
3805     else
3806     {
3807         bprintf("DEF(%-40s,0x%08x) // Found @0x%08x",name,fadr,atadr);
3808     }
3809     bprintf("\n");
3810 }
3811 
3812 uint32_t exm_typ_tbl=0, exm_typ_cnt=0;
3813 int print_exmem_types(firmware *fw)
3814 {
3815     if (exm_typ_tbl==0 || exm_typ_cnt==0)
3816         return 1;
3817     bprintf("// EXMEM types:\n");
3818     int ii = adr2idx(fw, exm_typ_tbl);
3819     int n;
3820     for (n=0; n<exm_typ_cnt; n++)
3821     {
3822         bprintf("// %s %i\n",adr2ptr(fw, fwval(fw,ii+n)),n);
3823     }
3824     bprintf("\n");
3825     return 0;
3826 }
3827 
3828 int find_exmem_alloc_table(firmware *fw)
3829 {
3830     int i = get_saved_sig(fw,"exmem_assert");
3831     if (i < 0)
3832     {
3833         return 0;
3834     }
3835     i = adr2idx(fw, func_names[i].val);
3836     uint32_t u;
3837     int n;
3838     for (n=1; n<16; n++)
3839     {
3840         if ( ((fwval(fw,i+n)&0xffff0000)==0xe59f0000) ) // ldr rx, [pc, #imm]
3841         {
3842             u = LDR2val(fw, i+n);
3843             if (u>fw->base && u<fw->base+fw->size*4-4 && (u&3)==0)
3844             {
3845                 break;
3846             }
3847         }
3848         u = 0;
3849     }
3850     if (u)
3851     {
3852         exm_typ_tbl = u;
3853         int ii = adr2idx(fw, exm_typ_tbl);
3854         char* extyp;
3855         for (n=0; n<32; n++)
3856         {
3857             if ( (fwval(fw,ii+n)!=0) && isASCIIstring(fw, fwval(fw,ii+n)) )
3858             {
3859                 extyp = adr2ptr(fw, fwval(fw,ii+n));
3860                 if ( strncmp(extyp,"EXMEM",5)==0 )
3861                 {
3862                     exm_typ_cnt++;
3863                 }
3864             }
3865             else
3866             {
3867                 break;
3868             }
3869         }
3870     }
3871 
3872     for (n=1; n<54; n++)
3873     {
3874         if ( ((fwval(fw,i+n)&0xffff0000)==0xe59f0000) ) // ldr rx, [pc, #imm]
3875         {
3876             u = LDR2val(fw, i+n);
3877             if (u>fw->data_start && u<fw->data_start+fw->data_len*4 && (fwRd(fw,i+n)>3))
3878             {
3879                 break;
3880             }
3881         }
3882         u = 0;
3883     }
3884     if (u)
3885     {
3886         print_stubs_min(fw,"exmem_alloc_table",u,idx2adr(fw,i+n));
3887     }
3888     if (exm_typ_tbl)
3889     {
3890         print_stubs_min(fw,"exmem_types_table",exm_typ_tbl,exm_typ_tbl);
3891     }
3892     if (exm_typ_cnt)
3893     {
3894         bprintf("DEF_CONST(%-34s,0x%08x)\n","exmem_type_count",exm_typ_cnt);
3895     }
3896     return 0;
3897 }
3898 
3899 int match_levent_table(firmware *fw, int k, uint32_t v1, uint32_t v2)
3900 {
3901     if ((fw->buf[k] > fw->base) && (fw->buf[k+1] == 0x00000800) && (fw->buf[k+2] == 0x00000002))
3902     {
3903         print_stubs_min(fw,"levent_table",idx2adr(fw,k),idx2adr(fw,k));
3904 #ifdef PRINT_LEVENT_TABLE
3905         uint32_t levent_tbl = idx2adr(fw,k);
3906         void write_levent_table_dump(firmware*, uint32_t);
3907         write_levent_table_dump(fw, levent_tbl);
3908 #endif
3909     }
3910     return 0;
3911 }
3912 
3913 int match_movie_status(firmware *fw, int k, uint32_t v1, uint32_t v2)
3914 {
3915     if (isLDR_PC(fw, k) &&                              // LDR R0, =base
3916         ((fw->buf[k+1] & 0xFE0F0000) == 0xE20F0000) &&  // ADR R1, =sub
3917         isSTR(fw, k+2) &&                               // STR R1, [R0,N]
3918         (fw->buf[k+3] == 0xE3A01003) &&                 // MOV R1, 3
3919         isSTR(fw, k+4) &&                               // STR R1, [R0,ofst]
3920         (LDR2val(fw,k) < fw->base))
3921     {
3922         uint32_t base = LDR2val(fw,k);
3923         uint32_t ofst = fw->buf[k+4] & 0x00000FFF;
3924         print_stubs_min(fw,"movie_status",base+ofst,idx2adr(fw,k));
3925         return 1;
3926     }
3927     else
3928     if (isLDR_PC(fw, k) &&                              // LDR R1, =sub
3929         isLDR_PC(fw, k+1) &&                            // LDR R0, =base
3930         isSTR(fw, k+2) &&                               // STR R1, [R0,N]
3931         (fw->buf[k+3] == 0xE3A01003) &&                 // MOV R1, 3
3932         isSTR(fw, k+4) &&                               // STR R1, [R0,ofst]
3933         (LDR2val(fw,k+1) < fw->base))
3934     {
3935         uint32_t base = LDR2val(fw,k+1);
3936         uint32_t ofst = fw->buf[k+4] & 0x00000FFF;
3937         print_stubs_min(fw,"movie_status",base+ofst,idx2adr(fw,k));
3938         return 1;
3939     }
3940     else
3941     if (isLDR_PC(fw, k) &&                                      // LDR Rx, =base
3942         isLDR(fw, k+1) && (fwRd(fw,k) == fwRn(fw,k+1)) &&       // LDR R0, [Rx, ...]
3943         isCMP(fw, k+2) && (fwRd(fw,k+2) == fwRd(fw,k+1)) &&     // CMP R0, #...
3944         (fwval(fw,k+3) == 0x03A00005) &&
3945         isSTR_cond(fw, k+4) && (fwRn(fw,k+4) == fwRd(fw,k)) &&  // STRxx R0, [Rx,ofst]
3946         (LDR2val(fw,k) < fw->base))
3947     {
3948         uint32_t base = LDR2val(fw,k);
3949         uint32_t ofst = fwOp2(fw,k+4);
3950         print_stubs_min(fw,"movie_status",base+ofst,idx2adr(fw,k));
3951         return 1;
3952     }
3953     return 0;
3954 }
3955 
3956 int match_full_screen_refresh(firmware *fw, int k, uint32_t v1, uint32_t v2)
3957 {
3958     if (((fw->buf[k] & 0xFF1FF000) == 0xE51F0000) &&    // LDR R0, =base
3959         (fw->buf[k+1] == 0xE5D01000) &&                 // LDRB R1, [R0]
3960         (fw->buf[k+2] == 0xE3811002) &&                 // ORR R1, R1, #2
3961         (fw->buf[k+3] == 0xE5C01000) &&                 // STRB R1, [R0]
3962         isBX_LR(fw,k+4))                                // BX LR
3963     {
3964         uint32_t base = LDR2val(fw,k);
3965         print_stubs_min(fw,"full_screen_refresh",base,idx2adr(fw,k));
3966     }
3967     return 0;
3968 }
3969 
3970 int match_canon_shoot_menu_active(firmware *fw, int k, uint32_t v1, uint32_t v2)
3971 {
3972     if (((fw->buf[k]   & 0xFF1FF000) == 0xE51F1000) &&  // LDR R1, =base
3973         ((fw->buf[k+1] & 0xFFFFF000) == 0xE5D10000) &&  // LDRB R0, [R1, #n]
3974         (fw->buf[k+2] == 0xE2800001) &&                 // ADD R0, R0, #1
3975         ((fw->buf[k+3] & 0xFFFFF000) == 0xE5C10000) &&  // STRB R0, [R1, #n]
3976         (isB(fw,k+4)))                                  // B
3977     {
3978         uint32_t base = LDR2val(fw,k);
3979         uint32_t ofst = fw->buf[k+1] & 0x00000FFF;
3980         print_stubs_min(fw,"canon_shoot_menu_active",base+ofst,idx2adr(fw,k));
3981     }
3982     else
3983     if (((fw->buf[k]   & 0xFF1FF000) == 0xE51F0000) &&  // LDR R0, =base
3984         ((fw->buf[k+1] & 0xFFFFF000) == 0xE5D01000) &&  // LDRB R1, [R0, #n]
3985         (fw->buf[k+2] == 0xE2811001) &&                 // ADD R1, R1, #1
3986         ((fw->buf[k+3] & 0xFFFFF000) == 0xE5C01000) &&  // STRB R1, [R0, #n]
3987         (isB(fw,k+4)))                                  // B
3988     {
3989         uint32_t base = LDR2val(fw,k);
3990         uint32_t ofst = fw->buf[k+1] & 0x00000FFF;
3991         print_stubs_min(fw,"canon_shoot_menu_active",base+ofst,idx2adr(fw,k));
3992     }
3993     return 0;
3994 }
3995 
3996 int match_playrec_mode(firmware *fw, int k, uint32_t v1, uint32_t v2)
3997 {
3998     if (((fw->buf[k]    & 0xFF1FF000) == 0xE51F1000) && // LDR R1, =base
3999         ((fw->buf[k+1]  & 0xFFFFF000) == 0xE5810000) && // STR R0, [R1, #n]
4000         ((fw->buf[k+3]  & 0xFF1FF000) == 0xE51F0000) && // LDR R0, =base
4001         ((fw->buf[k+4]  & 0xFFFFF000) == 0xE5900000) && // LDR R0, [R0, #n]
4002         ((fw->buf[k+6]  & 0xFF1FF000) == 0xE51F1000) && // LDR R1, =base
4003         ((fw->buf[k+9]  & 0xFF1FF000) == 0xE51F0000) && // LDR R0, =base
4004         ((fw->buf[k+12] & 0xFF1FF000) == 0xE51F1000) && // LDR R1, =base
4005         ((fw->buf[k+15] & 0xFF1FF000) == 0xE51F0000) && // LDR R0, =base
4006         ((fw->buf[k+18] & 0xFF1FF000) == 0xE51F1000) && // LDR R1, =base
4007         (LDR2val(fw,k) == LDR2val(fw,k+3)) &&
4008         (LDR2val(fw,k) == LDR2val(fw,k+6)) &&
4009         (LDR2val(fw,k) == LDR2val(fw,k+9)) &&
4010         (LDR2val(fw,k) == LDR2val(fw,k+12)) &&
4011         (LDR2val(fw,k) == LDR2val(fw,k+15)) &&
4012         (LDR2val(fw,k) == LDR2val(fw,k+18)))
4013     {
4014         uint32_t base = LDR2val(fw,k);
4015         uint32_t ofst = fw->buf[k+1] & 0x00000FFF;
4016         print_stubs_min(fw,"playrec_mode",base+ofst,idx2adr(fw,k));
4017     }
4018     return 0;
4019 }
4020 
4021 int match_some_flag_for_af_scan(firmware *fw, int k, uint32_t v1, uint32_t v2)
4022 {
4023     if (isB(fw,k)   &&  // B loc
4024         isB(fw,k+1) &&  // B loc
4025         isB(fw,k+2) &&  // B loc
4026         isB(fw,k+3) &&  // B loc
4027         isB(fw,k+4) &&  // B loc
4028         isB(fw,k+5) &&  // B loc
4029         isB(fw,k+6) &&  // B loc
4030         isB(fw,k+7) &&  // B loc
4031         (followBranch(fw,idx2adr(fw,k),1) != followBranch(fw,idx2adr(fw,k+1),1)) &&
4032         (followBranch(fw,idx2adr(fw,k),1) == followBranch(fw,idx2adr(fw,k+2),1)) &&
4033         (followBranch(fw,idx2adr(fw,k),1) == followBranch(fw,idx2adr(fw,k+3),1)) &&
4034         (followBranch(fw,idx2adr(fw,k),1) != followBranch(fw,idx2adr(fw,k+4),1)) &&
4035         (followBranch(fw,idx2adr(fw,k),1) != followBranch(fw,idx2adr(fw,k+5),1)) &&
4036         (followBranch(fw,idx2adr(fw,k),1) == followBranch(fw,idx2adr(fw,k+6),1)) &&
4037         (followBranch(fw,idx2adr(fw,k),1) == followBranch(fw,idx2adr(fw,k+7),1)) &&
4038         (isLDR_PC(fw,adr2idx(fw,followBranch(fw,idx2adr(fw,k),1)))))    // LDR R0, =base
4039     {
4040         uint32_t base = LDR2val(fw,adr2idx(fw,followBranch(fw,idx2adr(fw,k),1)));
4041         if (base < fw->base)
4042             print_stubs_min(fw,"some_flag_for_af_scan",base,followBranch(fw,idx2adr(fw,k),1));
4043     }
4044     return 0;
4045 }
4046 
4047 int match_palette_data(firmware *fw, int k, uint32_t v1, uint32_t v2)
4048 {
4049     if ((fw->buf[k] == 0) && (fw->buf[k+1] == 0x00FF0000) &&
4050         (fw->buf[k+577] == 1) && (fw->buf[k+578] == 0x00FF0000) &&
4051         (fw->buf[k+1154] == 2) && (fw->buf[k+1155] == 0x00FF0000))
4052     {
4053         return idx2adr(fw,k);
4054     }
4055     else if ((fw->buf[k] == 0) && (fw->buf[k+1] == 0x00FF0000) &&
4056              (fw->buf[k+513] == 1) && (fw->buf[k+514] == 0x00FF0000) &&
4057              (fw->buf[k+1026] == 2) && (fw->buf[k+1027] == 0x00FF0000))
4058     {
4059         return idx2adr(fw,k);
4060     }
4061     return 0;
4062 }
4063 
4064 int match_palette_buffer_offset(firmware *fw, int k)
4065 {
4066     int idx2 = idxFollowBranch(fw, k, 0x01000001);
4067     if (isLDR(fw, idx2+2) && isBL(fw, idx2+3))
4068     {
4069         uint32_t palette_size = LDR2val(fw,idx2+2);
4070         if (palette_size >= 0x400)
4071         {
4072             bprintf("// Offset from start of palette_buffer to color data = %d (Found @0x%08x)\n",palette_size-0x400,idx2adr(fw,idx2+2));
4073             return 1;
4074         }
4075     }
4076     else if (isADR(fw, idx2+2) && isBL(fw, idx2+3))
4077     {
4078         uint32_t palette_size = ALUop2(fw,idx2+2);
4079         if (palette_size >= 0x400)
4080         {
4081             bprintf("// Offset from start of palette_buffer to color data = %d (Found @0x%08x)\n",palette_size-0x400,idx2adr(fw,idx2+2));
4082             return 1;
4083         }
4084     }
4085     return 0;
4086 }
4087 
4088 int match_palette_data3(firmware *fw, int k, uint32_t palette_data, uint32_t v2)
4089 {
4090     if (isLDR_PC(fw, k) && (LDR2val(fw,k) == palette_data) && isLDR_PC(fw,k-1) && isLDR_PC(fw,k-6) && isLDR(fw,k-5))
4091     {
4092         int palette_control = LDR2val(fw,k-6);
4093         int ptr_offset = fwOp2(fw,k-5);
4094         uint32_t fadr = find_inst_rev(fw, isSTMFD_LR, k-7, 30);
4095         if (fadr > 0)
4096         {
4097             int k1 = search_fw(fw, find_B, fadr, 0, 1);
4098             if ((k1 > 0) && isLDR_PC(fw,k1-2) && isLDR(fw,k1-1) && (LDR2val(fw,k1-2) == palette_control))
4099             {
4100                 int active_offset = fwOp2(fw,k1-1);
4101                 print_stubs_min(fw,"active_palette_buffer",palette_control+active_offset,idx2adr(fw,k1-1));
4102                 print_stubs_min(fw,"palette_buffer_ptr",palette_control+ptr_offset,idx2adr(fw,k-5));
4103                 if (isBL(fw,k+8))
4104                 {
4105                     fadr = followBranch(fw, idx2adr(fw,k+8), 0x01000001);
4106                     int idx = adr2idx(fw, fadr);
4107                     if (isLDR(fw, idx+2) && isBL(fw, idx+3))
4108                     {
4109                         uint32_t palette_size = LDR2val(fw,idx+2);
4110                         if (palette_size >= 0x400)
4111                         {
4112                             bprintf("// Offset from start of palette_buffer to color data = %d (Found @0x%08x)\n",palette_size-0x400,idx2adr(fw,idx+2));
4113                         }
4114                     }
4115                 }
4116                 return 1;
4117             }
4118         }
4119     }
4120     return 0;
4121 }
4122 
4123 int match_palette_data2(firmware *fw, int k, uint32_t v1, uint32_t v2)
4124 {
4125     if (isLDR(fw,k) && (LDR2val(fw,k) == v1))
4126     {
4127         int k1;
4128         for (k1=k+1; k1<k+20; k1++)
4129         {
4130             if (isBL(fw,k1) && isLDMFD(fw,k1+2))
4131             {
4132                 uint32_t fadr = followBranch(fw, idx2adr(fw,k1), 0x01000001);
4133                 int idx = adr2idx(fw, fadr);
4134                 int k2;
4135                 for (k2=idx; k2<idx+40; k2++)
4136                 {
4137                     if (isSTR(fw,k2) && isLDMFD(fw,k2+1))
4138                     {
4139                         int ptr_offset = fwval(fw,k2) & 0xFFF;
4140                         print_stubs_min(fw,"palette_buffer_ptr",v2+ptr_offset,idx2adr(fw,k2));
4141                         int found = 0;
4142                         for (k=idx; (k<idx+16) && !found; k++)
4143                         {
4144                             if (isBL(fw,k) && isCMP(fw,k+1) && isADR_PC(fw,k+2))
4145                             {
4146                                 fadr = ADR2adr(fw,k+2);
4147                                 idx = adr2idx(fw, fadr);
4148                                 int k3;
4149                                 for (k3=idx; (k3<idx+16) && !found; k3++)
4150                                 {
4151                                     if (isBL(fw,k3))
4152                                     {
4153                                         if (match_palette_buffer_offset(fw,k3))
4154                                             return 1;
4155                                     }
4156                                 }
4157                             }
4158                         }
4159                         return 1;
4160                     }
4161                 }
4162             }
4163             else if (isLDR_cond(fw,k1) && isLDMFD(fw,k1+2) && isBL(fw,k1-2))
4164             {
4165                 int ptr_offset = fwval(fw,k1) & 0xFFF;
4166                 print_stubs_min(fw,"palette_buffer_ptr",v2+ptr_offset,idx2adr(fw,k1));
4167                 match_palette_buffer_offset(fw, k1-2);
4168                 return 1;
4169             }
4170         }
4171     }
4172     return 0;
4173 }
4174 
4175 int match_SavePaletteData(firmware *fw, int idx, int palette_data)
4176 {
4177     if (isBL(fw,idx+13))
4178     {
4179         uint32_t fadr = followBranch(fw, idx2adr(fw,idx+13), 0x01000001);
4180         idx = adr2idx(fw, fadr);
4181         if (isLDR(fw,idx) && isLDR(fw,idx+1) && isB(fw,idx+2))
4182         {
4183             uint32_t palette_control = LDR2val(fw,idx);
4184             print_stubs_min(fw,"palette_control",palette_control,idx2adr(fw,idx));
4185             int active_offset = fwval(fw,idx+1) & 0xFFF;
4186             print_stubs_min(fw,"active_palette_buffer",palette_control+active_offset,idx2adr(fw,idx+1));
4187             fadr = followBranch(fw,idx2adr(fw,idx+2),1);
4188             idx = adr2idx(fw, fadr);
4189             if (isLDR(fw,idx+17) && isLDR(fw,idx+18) && isLDR(fw,idx+12) && (LDR2val(fw,idx+12) == palette_control))
4190             {
4191                 if (isLDR(fw,idx+13))
4192                 {
4193                     int ptr_offset = fwval(fw,idx+13) & 0xFFF;
4194                     print_stubs_min(fw,"palette_buffer_ptr",palette_control+ptr_offset,idx2adr(fw,idx+13));
4195                 }
4196                 int palette_buffer;
4197                 if ((fwval(fw,idx+18) & 0x0000F000) == 0)
4198                 {
4199                     palette_buffer = LDR2val(fw,idx+17);
4200                     print_stubs_min(fw,"palette_buffer",palette_buffer,idx2adr(fw,idx+17));
4201                 }
4202                 else
4203                 {
4204                     palette_buffer = LDR2val(fw,idx+18);
4205                     print_stubs_min(fw,"palette_buffer",palette_buffer,idx2adr(fw,idx+18));
4206                 }
4207                 if (isBL(fw,idx+26))
4208                 {
4209                     fadr = followBranch(fw, idx2adr(fw,idx+26), 0x01000001);
4210                     idx = adr2idx(fw, fadr);
4211                     if (isLDR(fw, idx+2) && isBL(fw, idx+3))
4212                     {
4213                         uint32_t palette_size = LDR2val(fw,idx+2);
4214                         if (palette_size >= 0x400)
4215                         {
4216                             bprintf("// Offset from start of palette_buffer to color data = %d (Found @0x%08x)\n",palette_size-0x400,idx2adr(fw,idx+2));
4217                         }
4218                     }
4219                 }
4220             }
4221         }
4222         else if (isLDR(fw,idx) && isLDR(fw,idx+6) && isLDR(fw,idx+7) && isBX(fw,idx+8))
4223         {
4224             int active_offset = -1;
4225             if ((fwval(fw,idx+6) & 0x0000F000) == 0)
4226                 active_offset = fwval(fw,idx+6) & 0xFFF;
4227             else if ((fwval(fw,idx+7) & 0x0000F000) == 0)
4228                 active_offset = fwval(fw,idx+7) & 0xFFF;
4229             if (active_offset >= 0)
4230             {
4231                 uint32_t palette_control = LDR2val(fw,idx);
4232                 //print_stubs_min(fw,"palette_control",palette_control,idx2adr(fw,idx));
4233                 print_stubs_min(fw,"active_palette_buffer",palette_control+active_offset,idx2adr(fw,idx+1));
4234                 search_fw(fw, match_palette_data2, palette_data, palette_control, 1);
4235             }
4236         }
4237         return 1;
4238     }
4239 
4240     return 0;
4241 }
4242 
4243 int match_viewport_address3(firmware *fw, int k, uint32_t v1, uint32_t v2)
4244 {
4245     if (isLDR_PC(fw,k) && (LDR2val(fw,k) == v1))
4246     {
4247         // Scan back to start of function
4248         int k1 = find_inst_rev(fw, isSTMFD_LR, k-1, 1000);
4249         if (k1 > 0)
4250         {
4251             // Check if function sig matches what we want
4252             if (isLDR_PC(fw,k1+1) && isLDR_PC(fw,k1+2) && isLDR(fw,k1+3) &&
4253                 (fwRd(fw,k1+1) == fwRn(fw,k1+3)))
4254             {
4255                 uint32_t a = LDR2val(fw,k1+1);
4256                 print_stubs_min(fw,"viewport_buffers",v1,idx2adr(fw,k));
4257                 print_stubs_min(fw,"active_viewport_buffer",a,idx2adr(fw,k1+1));
4258                 return 1;
4259             }
4260             else
4261             if (isLDR_PC(fw,k1+1) && isLDR_PC(fw,k1+3) && isLDR(fw,k1+4) &&
4262                 (fwRd(fw,k1+1) == fwRn(fw,k1+4)))
4263             {
4264                 uint32_t a = LDR2val(fw,k1+1);
4265                 print_stubs_min(fw,"viewport_buffers",v1,idx2adr(fw,k));
4266                 print_stubs_min(fw,"active_viewport_buffer",a,idx2adr(fw,k1+1));
4267                 return 1;
4268             }
4269             else
4270             if (isLDR_PC(fw,k1+1) && isLDR_PC(fw,k1+4) && isLDR(fw,k1+5) &&
4271                 (fwRd(fw,k1+1) == fwRn(fw,k1+5)))
4272             {
4273                 uint32_t a = LDR2val(fw,k1+1);
4274                 print_stubs_min(fw,"viewport_buffers",v1,idx2adr(fw,k));
4275                 print_stubs_min(fw,"active_viewport_buffer",a,idx2adr(fw,k1+1));
4276                 return 1;
4277             }
4278         }
4279     }
4280     return 0;
4281 }
4282 
4283 int match_viewport_address2(firmware *fw, int k, uint32_t v1, uint32_t v2)
4284 {
4285     if (fw->buf[k] == v1)
4286     {
4287         if (search_fw(fw, match_viewport_address3, v1, 0, 1))
4288             return 1;
4289     }
4290     return 0;
4291 }
4292 
4293 int match_viewport_address(firmware *fw, int k, uint32_t v1, uint32_t v2)
4294 {
4295     if (fw->buf[k] == v1)
4296     {
4297         // Find location in firmware that points to viewport address
4298         if (search_fw(fw, match_viewport_address2, idx2adr(fw,k), 0, 1))
4299             return 1;
4300     }
4301     return 0;
4302 }
4303 
4304 int match_physw_status(firmware *fw, int k, int v)
4305 {
4306     if (isLDR_PC(fw,k))
4307     {
4308         print_stubs_min(fw,"physw_status",LDR2val(fw,k),idx2adr(fw,k));
4309     }
4310 
4311     return 0;
4312 }
4313 
4314 int match_physw_run(firmware *fw, int k, int v)
4315 {
4316     if (isLDR_PC(fw,k))
4317     {
4318         uint32_t base = LDR2val(fw,k);
4319         uint32_t fadr = followBranch(fw, idx2adr(fw,k+1), 1);
4320         uint32_t ofst = fw->buf[adr2idx(fw,fadr)] & 0x00000FFF;
4321         print_stubs_min(fw,"physw_run",base+ofst,idx2adr(fw,k));
4322 
4323         ofst = fw->buf[k+2] & 0x00000FFF;
4324         print_stubs_min(fw,"physw_sleep_delay",base+ofst,idx2adr(fw,k));
4325     }
4326 
4327     return 0;
4328 }
4329 
4330 int match_canon_menu_active(firmware *fw, int k, int v)
4331 {
4332     if (isLDR_PC(fw,k))
4333     {
4334         uint32_t base = LDR2val(fw,k);
4335         int k1;
4336         for (k1=k+1; k1<k+5; k1++)
4337         {
4338             if (isLDR(fw,k1))
4339             {
4340                 uint32_t ofst = fw->buf[k1] & 0x00000FFF;
4341                 print_stubs_min(fw,"canon_menu_active",base+ofst,idx2adr(fw,k));
4342             }
4343         }
4344     }
4345 
4346     return 0;
4347 }
4348 
4349 int match_zoom_busy(firmware *fw, int k, int v)
4350 {
4351     if (isBL(fw,k))
4352     {
4353         int idx1 = idxFollowBranch(fw,k,0x01000001);
4354         int k1;
4355         for (k1=idx1; k1<idx1+50; k1++)
4356         {
4357             if ((fw->buf[k1] & 0xFFFF0000) == 0xE8BD0000)   // LDMFD
4358             {
4359                 uint32_t fadr = 0;
4360                 if (isADR_PC(fw,k1+1))
4361                 {
4362                     fadr = ADR2adr(fw,k1+1);
4363                 }
4364                 else if (isADR_PC(fw,k1+2))
4365                 {
4366                     fadr = ADR2adr(fw,k1+2);
4367                 }
4368                 else if (isADR_PC(fw,k1-3))
4369                 {
4370                     fadr = ADR2adr(fw,k1-3);
4371                 }
4372                 else if (isLDR_PC(fw,k1+1))
4373                 {
4374                     fadr = LDR2val(fw,k1+1);
4375                 }
4376                 else if (isLDR_PC(fw,k1+2))
4377                 {
4378                     fadr = LDR2val(fw,k1+2);
4379                 }
4380                 if (fadr != 0)
4381                 {
4382                     int idx2 = adr2idx(fw,fadr);
4383                     if (isLDR_PC(fw,idx2+1) && isLDR(fw,idx2+2))
4384                     {
4385                         int base = LDR2val(fw,idx2+1);
4386                         int ofst = fw->buf[idx2+2] & 0xFFF;
4387                            print_stubs_min(fw,"zoom_busy",base+ofst-4,fadr);
4388                         break;
4389                     }
4390                 }
4391             }
4392         }
4393     }
4394 
4395     return 0;
4396 }
4397 
4398 int match_focus_busy(firmware *fw, int k, int v)
4399 {
4400     if ((fw->buf[k] & 0xFFFF0000) == 0xE8BD0000)   // LDMFD
4401     {
4402         int k1 = 0;
4403         if (isBL(fw,k-2))
4404         {
4405             k1 = idxFollowBranch(fw,k-2,0x01000001);
4406         }
4407         if (isBL(fw,k-1))
4408         {
4409             k1 = idxFollowBranch(fw,k-1,0x01000001);
4410         }
4411         if (k1 != 0)
4412         {
4413             if (isLDR_PC(fw,k1+1) && isLDR(fw,k1+3))
4414             {
4415                 int base = LDR2val(fw,k1+1);
4416                 int ofst = fw->buf[k1+3] & 0xFFF;
4417                    print_stubs_min(fw,"focus_busy",base+ofst-4,idx2adr(fw,k1));
4418                 return 1;
4419             }
4420         }
4421     }
4422 
4423     return 0;
4424 }
4425 
4426 int match_bitmap_buffer2(firmware *fw, int k, int v)
4427 {
4428     uint32_t screen_lock = idx2adr(fw,k);
4429     if (isBL(fw,v) && (followBranch(fw,idx2adr(fw,v),0x01000001) == screen_lock) && isBL(fw,v+2) && isBL(fw,v+3))
4430     {
4431         uint32_t fadr = followBranch2(fw,idx2adr(fw,v+3),0x01000001);
4432         int k1 = adr2idx(fw,fadr);
4433         if (isLDR_PC(fw,k1+1))
4434         {
4435             int reg = (fwval(fw,k1+1) & 0x0000F000) >> 12;
4436             uint32_t adr = LDR2val(fw,k1+1);
4437             int k2;
4438             for (k2=k1; k2<k1+32; k2++)
4439             {
4440                 if (isLDR_PC(fw,k2) && isLDR(fw,k2+1) && (((fwval(fw,k2+1) & 0x000F0000) >> 16) == reg))
4441                 {
4442                     uint32_t bitmap_buffer = LDR2val(fw,k2);
4443                     if (bitmap_buffer == (adr + 0x1C))
4444                     {
4445                         uint32_t active_bitmap_buffer = adr + (fwval(fw,k2+1) & 0xFFF);
4446                         print_stubs_min(fw,"bitmap_buffer",bitmap_buffer,idx2adr(fw,k2));
4447                         print_stubs_min(fw,"active_bitmap_buffer",active_bitmap_buffer,idx2adr(fw,k2+1));
4448                     }
4449                 }
4450             }
4451         }
4452     }
4453 
4454     return 0;
4455 }
4456 
4457 int match_bitmap_buffer(firmware *fw, int k, int v)
4458 {
4459     search_saved_sig(fw, "ScreenLock", match_bitmap_buffer2, k, 0, 1);
4460     return 0;
4461 }
4462 
4463 int match_raw_buffer(firmware *fw, int k, uint32_t rb1, uint32_t v2)
4464 {
4465     if (((fwval(fw,k) == rb1) && (fwval(fw,k+4) == rb1) && (fwval(fw,k-2) != 1)) ||
4466         ((fwval(fw,k) == rb1) && (fwval(fw,k+4) == rb1) && (fwval(fw,k+20) == rb1)))
4467     {
4468         uint32_t rb2 = fwval(fw,k+1);
4469         if ((rb1 != rb2) && (rb2 > 0))
4470         {
4471             bprintf("// Camera has 2 RAW buffers @ 0x%08x & 0x%08x\n", rb1, rb2, idx2adr(fw,k));
4472             bprintf("//  Note: active buffer --> raw_buffers[active_raw_buffer]\n");
4473             bprintf("//        other buffer  --> raw_buffers[active_raw_buffer^1]\n");
4474             print_stubs_min(fw,"raw_buffers",idx2adr(fw,k),idx2adr(fw,k));
4475         }
4476         return rb2;
4477     }
4478     else if ((fwval(fw,k) == rb1) && (fwval(fw,k-2) == 2) && (fwval(fw,k-7) == rb1))
4479     {
4480         uint32_t rb2 = fwval(fw,k+3);
4481         if ((rb1 != rb2) && (rb2 > 0))
4482         {
4483             bprintf("// Camera has 2 RAW buffers @ 0x%08x & 0x%08x\n", rb1, rb2, idx2adr(fw,k));
4484             bprintf("//  Note: active buffer --> raw_buffers[ active_raw_buffer   *3]\n");
4485             bprintf("//        other buffer  --> raw_buffers[(active_raw_buffer^1)*3]\n");
4486             print_stubs_min(fw,"raw_buffers",idx2adr(fw,k),idx2adr(fw,k));
4487         }
4488         return rb2;
4489     }
4490     return 0;
4491 }
4492 
4493 uint32_t frsp_buf = 0;
4494 uint32_t frsp_buf_at = 0;
4495 int find_DoMovieFrameCapture_buf(firmware *fw)
4496 {
4497     uint32_t uncached_adr = 0x10000000; // true for all vx cams
4498     int k = get_saved_sig(fw,"DoMovieFrameCapture");
4499     int ka = get_saved_sig(fw,"ClearEventFlag");
4500     if (k < 0 || ka < 0)
4501         return 0;
4502     k = adr2idx(fw, func_names[k].val);
4503     ka = adr2idx(fw, func_names[ka].val);
4504     if (k && ka)
4505     {
4506         int k2 = find_inst(fw,isBL,k,14);
4507         if (k2 == -1 || idxFollowBranch(fw,k2,0x01000001) != ka)
4508             return 0;
4509         int k1 = k;
4510         int reg = -1;
4511         while (k1<k2)
4512         {
4513             k1++;
4514             if (reg < 0 && isLDR_PC(fw,k1))
4515             {
4516                 uint32_t v = LDR2val(fw,k1);
4517                 if (v>uncached_adr && v<uncached_adr+fw->maxram && (v&3)==0)
4518                 {
4519                     frsp_buf = v;
4520                     frsp_buf_at = idx2adr(fw,k1);
4521                     break;
4522                 }
4523             }
4524             if (isMOV_immed(fw,k1) && ALUop2a(fw,k1)>uncached_adr)
4525             {
4526                 reg = fwRd(fw,k1);
4527                 frsp_buf = ALUop2a(fw,k1);
4528                 frsp_buf_at = idx2adr(fw, k1);
4529             }
4530             if (reg<0)
4531                 continue;
4532             if ((fwval(fw,k1)&0xfffff000) == (0xe2800000+(reg<<12)+(reg<<16))) // ADD Rx, Rx, #imm
4533             {
4534                 frsp_buf += ALUop2a(fw,k1);
4535                 frsp_buf_at = idx2adr(fw, k1);
4536             }
4537         }
4538     }
4539     if (!frsp_buf) // ixus30/40
4540     {
4541         k = get_saved_sig(fw,"WBInteg.DoCaptMovieFrame_FW");
4542         if (k < 0)
4543             return 0;
4544         k = adr2idx(fw, func_names[k].val);
4545         ka = find_inst(fw,isLDR_PC,k,6);
4546         if (ka < 0)
4547             return 0;
4548         uint32_t v = LDR2val(fw,ka);
4549         if (v>uncached_adr && v<uncached_adr+fw->maxram && (v&3)==0)
4550         {
4551             frsp_buf = v;
4552             frsp_buf_at = idx2adr(fw,ka);
4553         }
4554     }
4555     return 0;
4556 }
4557 
4558 // Search for things that go in 'stubs_min.S'
4559 void find_stubs_min(firmware *fw)
4560 {
4561     //int k,k1;
4562 
4563     out_hdr = 1;
4564     add_blankline();
4565 
4566     bprintf("// Values below can be overridden in 'stubs_min.S':\n");
4567 
4568     // Find 'levent_table'
4569     search_fw(fw, match_levent_table, 0, 0, 1);
4570 
4571     // Find 'FlashParamsTable'
4572     if (FlashParamsTable_address != 0)
4573         print_stubs_min(fw,"FlashParamsTable",FlashParamsTable_address,FlashParamsTable_address);
4574 
4575     find_FileAccessSem(fw);
4576 /*
4577     // Find 'physw_status'
4578     search_saved_sig(fw, "kbd_read_keys", match_physw_status, 0, 0, 5);
4579 
4580     // Find 'physw_run' & 'physw_sleep_delay'
4581     search_saved_sig(fw, "task_PhySw", match_physw_run, 0, 0, 5);
4582 
4583     // Find 'movie_status'
4584     search_fw(fw, match_movie_status, 0, 0, 1);
4585 
4586     // Find 'video_compression_rate'
4587     uint32_t sadr = find_str(fw, "CompressionRateAdjuster.c");
4588     k = find_nxt_str_ref(fw, sadr, -1);
4589     int found = 0;
4590     while ((k >= 0) && !found)
4591     {
4592         int f = find_inst_rev(fw, isSTMFD_LR, k-1, 100);
4593         if (f != -1)
4594         {
4595             f = search_fw(fw, find_BL, f, 0, 1);
4596             if (f > 0)
4597             {
4598                 f--;
4599                 if ((fwval(fw,f) & 0xFFF00000) == 0xE2400000)     // SUB
4600                 {
4601                     int src = fwRn(fw,f);
4602                     for (k1 = f-1; (k1 > f-10) && !found; k1--)
4603                     {
4604                         if (isLDR_PC(fw,k1) && (fwRd(fw,k1) == src))
4605                         {
4606                             uint32_t v = LDR2val(fw,k1) - ALUop2(fw,f);
4607                             print_stubs_min(fw,"video_compression_rate",v,idx2adr(fw,k1));
4608                             found = 1;
4609                         }
4610                     }
4611                 }
4612             }
4613         }
4614         k = find_nxt_str_ref(fw, sadr, k);
4615     }
4616 
4617     // Find 'full_screen_refresh'
4618     search_fw(fw, match_full_screen_refresh, 0, 0, 1);
4619 
4620     // Find 'canon_menu_active'
4621     search_saved_sig(fw, "StartRecModeMenu", match_canon_menu_active, 0, 0, 5);
4622 
4623     // Find 'canon_shoot_menu_active'
4624     search_fw(fw, match_canon_shoot_menu_active, 0, 0, 1);
4625 
4626     // Find 'playrec_mode'
4627     int found_playrec_mode = 0;
4628     k = find_str_ref(fw, "AFFChg");
4629     if ((k >= 0) && isBL(fw,k+6))
4630     {
4631         k = idxFollowBranch(fw, k+6, 0x01000001);
4632         if (isLDR_PC(fw,k) && isLDR(fw,k+1))
4633         {
4634             uint32_t base = LDR2val(fw,k);
4635             uint32_t ofst = fw->buf[k+1] & 0x00000FFF;
4636             print_stubs_min(fw,"playrec_mode",base+ofst,idx2adr(fw,k));
4637             found_playrec_mode = 1;
4638         }
4639     }
4640     if (!found_playrec_mode)
4641     {
4642         search_fw(fw, match_playrec_mode, 0, 0, 1);
4643     }
4644 
4645     // Find 'zoom_status'
4646     int found_zoom_status = 0;
4647 
4648     k = find_str_ref(fw, "m_ZoomState            :%d\n");
4649     if (k >= 0)
4650     {
4651         if (isLDR(fw,k-1))
4652         {
4653             uint32_t ofst = fw->buf[k-1] & 0x00000FFF;
4654             uint32_t reg = (fw->buf[k-1] & 0x000F0000) >> 16;
4655             uint32_t ldr_inst = 0xE51F0000 | (reg << 12);
4656             for (k1=k-2; k1>k-20; k1--)
4657             {
4658                 if ((fw->buf[k1] & 0xFF1FF000) == ldr_inst)
4659                 {
4660                     uint32_t base = LDR2val(fw,k1);
4661                     print_stubs_min(fw,"zoom_status",base+ofst,idx2adr(fw,k));
4662                     found_zoom_status = 1;
4663                     break;
4664                 }
4665             }
4666         }
4667     }
4668 
4669     if (!found_zoom_status)
4670     {
4671         for (k=0; k<fw->size; k++)
4672         {
4673             if (((fw->buf[k] & 0xFF1FF000) == 0xE51F0000) &&    // LDR R0, =base
4674                 (fw->buf[k+1] == 0xE5D00000) &&                 // LDRB R0, [R0]
4675                 (fw->buf[k+2] == 0xE1B00000) &&                 // MOVS R0, R0
4676                 (fw->buf[k+3] == 0x13A00001) &&                 // MOVNE R0, #1
4677                 isBX_LR(fw,k+4))                                // BX LR
4678             {
4679                 uint32_t base = LDR2val(fw,k);
4680                 print_stubs_min(fw,"zoom_status",base,idx2adr(fw,k));
4681                 found_zoom_status = 1;
4682                 //break;
4683             }
4684         }
4685     }
4686 
4687     if (!found_zoom_status)
4688     {
4689         k = find_str_ref(fw, "TerminateDeliverToZoomController");
4690         if (k >= 0)
4691         {
4692             for (k1=0; k1<5; k1++)
4693             {
4694                 if (isLDR_PC(fw,k+k1))
4695                 {
4696                     uint32_t base = LDR2val(fw,k+k1);
4697                     print_stubs_min(fw,"zoom_status",base+0x20,idx2adr(fw,k+k1));
4698                     found_zoom_status = 1;
4699                     break;
4700                 }
4701             }
4702         }
4703     }
4704 
4705     // Find 'some_flag_for_af_scan'
4706     search_fw(fw, match_some_flag_for_af_scan, 0, 0, 1);
4707 
4708     // focus_len_table
4709     if (fw->sv->min_focus_len != 0)
4710     {
4711         int found = 0, pos = 0, len = 0, size = 0;
4712         for (k=0; k<fw->size; k++)
4713         {
4714             if (fw->buf[k] == fw->sv->min_focus_len)
4715             {
4716                 int mul = 1;
4717                 if ((fw->buf[k+1] == 100) && (fw->buf[k+2] == 0)) mul = 3;
4718                 if ((fw->buf[k+1] == 100) && (fw->buf[k+2] != 0)) mul = 2;
4719                 if ((fw->buf[k+1] ==   0) && (fw->buf[k+2] != 0)) mul = 2;
4720                 for (k1 = k + mul; (k1 < fw->size) && (fw->buf[k1] > fw->buf[k1-mul]) && (fw->buf[k1] > fw->sv->min_focus_len) && (fw->buf[k1] < fw->sv->max_focus_len); k1 += mul) ;
4721                 if (fw->buf[k1] == fw->sv->max_focus_len)
4722                 {
4723                     if ((found == 0) || ((size < mul) && (len < ((k1 - k) / mul) + 1)))
4724                     {
4725                         found = 1;
4726                         pos = k;
4727                         len = ((k1 - k) / mul) + 1;
4728                         size = mul;
4729                     }
4730                 }
4731             }
4732         }
4733         if (found == 1)
4734         {
4735             bprintf("// focus_len_table contains zoom focus lengths for use in 'get_focal_length' (main.c).\n");
4736             if (size == 1)
4737                 bprintf("// each entry contains 1 int value, which is the the zoom focus length.\n",size);
4738             else
4739                 bprintf("// each entry contains %d int value(s), the first is the zoom focus length.\n",size);
4740             bprintf("// there are %d entries in the table - set NUM_FL to %d\n",len,len);
4741             print_stubs_min(fw,"focus_len_table",idx2adr(fw,pos),idx2adr(fw,pos));
4742         }
4743     }
4744 
4745     // Find 'zoom_busy'
4746     search_saved_sig(fw, "ResetZoomLens", match_zoom_busy, 0, 0, 5);
4747 
4748     // Find 'focus_busy'
4749     search_saved_sig(fw, "ResetFocusLens", match_focus_busy, 0, 0, 25);
4750 
4751     // Find 'recreview_hold'
4752     k = find_str_ref(fw, "ShootCon_NotifyStartReviewHold");
4753     if (k >= 0)
4754     {
4755         for (k1=k; k1<k+20; k1++)
4756         {
4757             if (isLDR_PC(fw,k1) && ((fw->buf[k1+1] & 0xFFFF0FFF) == 0xE3A00001) && isSTR(fw,k1+2) &&
4758                 ((fw->buf[k1+1] & 0x0000F000) == (fw->buf[k1+2] & 0x0000F000)) &&
4759                 ((fw->buf[k1] & 0x0000F000) == ((fw->buf[k1+2] & 0x000F0000) >> 4)))
4760             {
4761                 uint32_t base = LDR2val(fw,k1);
4762                 int ofst = fw->buf[k1+2] & 0x00000FFF;
4763                 print_stubs_min(fw,"recreview_hold",base+ofst,idx2adr(fw,k1));
4764                 break;
4765             }
4766         }
4767     }
4768 
4769     // Find palette colour data
4770     uint32_t palette_data = search_fw(fw, match_palette_data, 0, 0, 1);
4771 
4772     // Find 'palette buffer' info
4773     if (palette_data)
4774     {
4775         bprintf("// Palette colour tables  found @ 0x%08x\n", palette_data);
4776         if (search_saved_sig(fw, "SavePaletteData", match_SavePaletteData, palette_data, 0, 1) == 0)
4777         {
4778             search_fw(fw, match_palette_data3, palette_data, 0, 1);
4779         }
4780     }
4781 
4782     // Find 'bitmap buffer' info
4783     search_saved_sig(fw, "GUISrv_StartGUISystem", match_bitmap_buffer, 0, 0, 50);
4784 
4785     // Get viewport address
4786     uint32_t v = find_viewport_address(fw,&k);
4787     if (k >= 0)
4788     {
4789         search_fw(fw, match_viewport_address, v, 0, 1);
4790     }
4791 
4792     // find 1st RAW buffer address
4793     k = find_str_ref(fw, "CRAW BUFF       %p");
4794     if (k >= 0)
4795     {
4796         int rb1_idx;
4797         uint32_t rb1 =0, rb2 = 0;
4798         if (isLDR(fw,k-1))
4799         {
4800             rb1 = LDR2val(fw,k-1);
4801             rb1_idx = k - 1;
4802         }
4803         else if (isMOV_immed(fw,k-1))
4804         {
4805             rb1 = ALUop2(fw,k-1);
4806             rb1_idx = k - 1;
4807         }
4808         else if (isMOV(fw,k-1) && (fwRd(fw,k-1) == 1))
4809         {
4810             int reg = fwval(fw,k-1) & 0xF;
4811             for (k1=k-2; k1>k-50; k1--)
4812             {
4813                 if (isLDR(fw,k1) && (fwRd(fw,k1) == reg))
4814                 {
4815                     rb1 = LDR2val(fw,k1);
4816                     rb1_idx = k1;
4817                     break;
4818                 }
4819             }
4820         }
4821         if (rb1 > 0)
4822         {
4823             found = 0;
4824             rb2 = search_fw(fw, match_raw_buffer, rb1, 0, 5);
4825             if ((rb2 > 0) && (rb1 != rb2))
4826             {
4827                 // Find 'active_raw_buffer'
4828                 sadr = find_str(fw, "SsImgProcBuf.c");
4829                 k = find_nxt_str_ref(fw, sadr, -1);
4830                 while ((k >= 0) && !found)
4831                 {
4832                     int f = find_inst_rev(fw, isSTMFD_LR, k-1, 100);
4833                     if (f != -1)
4834                     {
4835                         int e = find_inst(fw, isLDMFD_PC, f+1, 200);
4836                         for (k1 = f+1; k1 < e; k1++)
4837                         {
4838                             if (
4839                                 (
4840                                     ((fwval(fw,k1)   & 0xFFF00FFF) == 0xE2400001) &&    // SUB Rx, Rn, #1
4841                                     isLDR(fw,k1+1) &&                                   // LDR Ry, [Rz,
4842                                     ((fwval(fw,k1+2) & 0xFFF00000) == 0xE1500000) &&    // CMP Rx, Ry
4843                                     (((fwRd(fw,k1) == fwRd(fw,k1+2)) && (fwRd(fw,k1+1) == fwRn(fw,k1+2))) ||
4844                                      ((fwRd(fw,k1) == fwRn(fw,k1+2)) && (fwRd(fw,k1+1) == fwRd(fw,k1+2)))) &&
4845                                     ((fwval(fw,k1+3) & 0xFFF00FFF) == 0x12800001) &&    // ADDNE Ry, Ry, #1
4846                                     ((fwRd(fw,k1+3) == fwRn(fw,k1+3)) && (fwRd(fw,k1+3) == fwRd(fw,k1+1))) &&
4847                                     ((fwval(fw,k1+4) & 0xFFF00FFF) == 0x03A00000) &&    // MOVEQ Ry, #0
4848                                     (fwRd(fw,k1+4) == fwRd(fw,k1+1)) &&
4849                                     isSTR(fw,k1+5) &&                                   // STR Ry, [Rz,
4850                                     ((fwRd(fw,k1+5) == fwRd(fw,k1+1)) && (fwRn(fw,k1+5) == fwRn(fw,k1+1)) && (fwOp2(fw,k1+5) == fwOp2(fw,k1+1)))
4851                                 ) ||
4852                                 (
4853                                     ((fwval(fw,k1)   & 0xFFF00FFF) == 0xE2400001) &&    // SUB Rx, Rn, #1
4854                                     isLDR(fw,k1+1) &&                                   // LDR Ry, [Rz,
4855                                     ((fwval(fw,k1+3) & 0xFFF00000) == 0xE1500000) &&    // CMP Rx, Ry
4856                                     (((fwRd(fw,k1) == fwRd(fw,k1+3)) && (fwRd(fw,k1+1) == fwRn(fw,k1+3))) ||
4857                                      ((fwRd(fw,k1) == fwRn(fw,k1+3)) && (fwRd(fw,k1+1) == fwRd(fw,k1+3)))) &&
4858                                     ((fwval(fw,k1+4) & 0xFFF00FFF) == 0x12800001) &&    // ADDNE Ry, Ry, #1
4859                                     ((fwRd(fw,k1+4) == fwRn(fw,k1+4)) && (fwRd(fw,k1+4) == fwRd(fw,k1+1))) &&
4860                                     ((fwval(fw,k1+5) & 0xFFF00FFF) == 0x03A00000) &&    // MOVEQ Ry, #0
4861                                     (fwRd(fw,k1+5) == fwRd(fw,k1+1)) &&
4862                                     isSTR(fw,k1+7) &&                                   // STR Ry, [Rz,
4863                                     ((fwRd(fw,k1+7) == fwRd(fw,k1+1)) && (fwRn(fw,k1+7) == fwRn(fw,k1+1)) && (fwOp2(fw,k1+7) == fwOp2(fw,k1+1)))
4864                                 )
4865                                )
4866                             {
4867                                 int ofst = fwOp2(fw,k1+1);
4868                                 int reg = fwRn(fw,k1+1);
4869                                 int k2;
4870                                 for (k2 = f+1; (k2 < e) && !found; k2++)
4871                                 {
4872                                     if (isLDR_PC(fw,k2) && (fwRd(fw,k2) == reg))
4873                                     {
4874                                         uint32_t base = LDR2val(fw,k2);
4875                                         print_stubs_min(fw,"active_raw_buffer",base+ofst,idx2adr(fw,k1));
4876                                         found = 1;
4877                                         break;
4878                                     }
4879                                 }
4880                             }
4881                         }
4882                     }
4883                     k = find_nxt_str_ref(fw, sadr, k);
4884                 }
4885             }
4886             if (!found)
4887             {
4888                 bprintf("// Camera appears to have only 1 RAW buffer @ 0x%08x (Found @0x%08x)\n", rb1, idx2adr(fw,rb1_idx));
4889             }
4890         }
4891     }
4892 */
4893 
4894     // Find exmem allocation table
4895     find_exmem_alloc_table(fw);
4896 
4897     // Find imager_active
4898     search_saved_sig(fw, "ImagerActivate", match_imager_active, 0/*v*/, 0, 30);
4899 
4900 
4901 //    find_DoMovieFrameCapture_buf(fw);
4902 //    if (frsp_buf)
4903 //    {
4904 //        print_stubs_min(fw,"frsp_buf",frsp_buf,frsp_buf_at);
4905 //    }
4906 
4907     // Find UI property count
4908     search_saved_sig(fw, "PTM_SetCurrentItem", match_uiprop_count, 0, 0, 30);
4909 }
4910 
4911 //------------------------------------------------------------------------------------------------------------
4912 
4913 int find_ctypes(firmware *fw, int k)
4914 {
4915     static unsigned char ctypes[] =
4916     {
4917         0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60, 0x60, 0x60, 0x60, 0x60, 0x20, 0x20,
4918         0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
4919         0x48, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
4920         0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
4921         0x10, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4922         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x10, 0x10, 0x10, 0x10, 0x10,
4923         0x10, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 2, 2, 2, 2, 2, 2, 2, 2, 2,
4924         2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0x10, 0x10, 0x10, 0x10, 0x20
4925     };
4926 
4927     if (k < (fw->size*4 - sizeof(ctypes)))
4928     {
4929         if (memcmp(((char*)fw->buf)+k,ctypes,sizeof(ctypes)) == 0)
4930         {
4931             bprintf("DEF(ctypes, 0x%08x)\n", fw->base + k);
4932             return 1;
4933         }
4934     }
4935     return 0;
4936 }
4937 
4938 int match_nrflag3(firmware *fw, int k, uint32_t v1, uint32_t v2)
4939 {
4940     if (isBL(fw,k) && (idxFollowBranch(fw,k,0x01000001) == v1))
4941     {
4942         // Found call to function, work out R3 value passed in
4943         int ofst1 = 0;
4944         int k3, k4 = 0;
4945         for (k3=k; k3>k-30; k3--)
4946         {
4947             if ((fwval(fw,k3) & 0x0F0FF000) == 0x020D3000)       // Dest = R3, Src = SP = skip
4948                 break;
4949             if ((fwval(fw,k3) & 0xFF0FF000) == 0xE2033000)       // ADD/SUB R3,R3,x
4950             {
4951                 k4 = k3;
4952                 if ((fwval(fw,k3) & 0x00F00000) == 0x00400000)   // SUB
4953                     ofst1 -= (fwval(fw,k3) & 0x00000FFF);
4954                 else
4955                     ofst1 += (fwval(fw,k3) & 0x00000FFF);
4956             }
4957             if (isLDR_PC(fw,k3) && (fwRd(fw,k3) == 3))
4958             {
4959                 int ofst2 = LDR2val(fw,k3);
4960                 if (ofst2 > (fw->data_len*4 + fw->data_start)) // has to be in the preinited data section
4961                     return 0;
4962                 bprintf("\n// For capt_seq.c\n");
4963                 if (ofst1 == 0)
4964                 {
4965                     bprintf("DEF(_nrflag,0x%04x) // Found @ %08x (0x%04x)\n",ofst2,idx2adr(fw,k3),ofst2);
4966                     bprintf("//static long *nrflag = (long*)(0x%04x);       // Found @ %08x\n",ofst2,idx2adr(fw,k3));
4967                 }
4968                 else if (ofst1 < 0)
4969                 {
4970                     bprintf("DEF(_nrflag,0x%04x) // Found @ %08x (0x%04x) & %08x (-0x%02x)\n",ofst2+ofst1,idx2adr(fw,k3),ofst2,idx2adr(fw,k),-ofst1);
4971                     bprintf("//static long *nrflag = (long*)(0x%04x-0x%02x);  // Found @ %08x & %08x\n",ofst2,-ofst1,idx2adr(fw,k3),idx2adr(fw,k4));
4972                 }
4973                 else
4974                 {
4975                     bprintf("DEF(_nrflag,0x%04x) // Found @ %08x (0x%04x) & %08x (+0x%02x)\n",ofst2+ofst1,idx2adr(fw,k3),ofst2,idx2adr(fw,k),ofst1);
4976                     bprintf("//static long *nrflag = (long*)(0x%04x+0x%02x);  // Found @ %08x & %08x\n",ofst2,ofst1,idx2adr(fw,k3),idx2adr(fw,k4));
4977                 }
4978                 return 1;
4979             }
4980         }
4981     }
4982     return 0;
4983 }
4984 
4985 int match_nrflag(firmware *fw, int idx, int v)
4986 {
4987     int k1, k2, k3;
4988     int found = 0;
4989 
4990     if (isLDR(fw, idx+1) && isLDR(fw, idx+2))
4991     {
4992         k3 = idx+2;
4993         int ofst2 = LDR2val(fw, k3);
4994 
4995         for (k1=k3+1; k1<k3+8; k1++)
4996         {
4997             if (isB(fw, k1))
4998             {
4999                 k2 = idxFollowBranch(fw,k1,0x01000001);
5000                 if (isSTR(fw, k2))
5001                 {
5002                     found = 1;
5003                     break;
5004                 }
5005                 k2++;
5006                 if (isSTR(fw, k2))
5007                 {
5008                     found = 1;
5009                     break;
5010                 }
5011             }
5012         }
5013 
5014         if (found)
5015         {
5016             int ofst1 = fw->buf[k2] & 0x00000FFF;
5017             bprintf("\n// For capt_seq.c\n");
5018             bprintf("DEF(_nrflag,0x%04x) // Found @ %08x (0x%04x) & %08x (+0x%02x)\n",ofst2+ofst1,idx2adr(fw,k3),ofst2,idx2adr(fw,k2),ofst1);
5019             bprintf("//static long *nrflag = (long*)(0x%04x+0x%02x);  // Found @ %08x & %08x\n",ofst2,ofst1,idx2adr(fw,k3),idx2adr(fw,k2));
5020             bprintf("//#define NR_AUTO (0)                          // have to explictly reset value back to 0 to enable auto\n");
5021         }
5022     }
5023 
5024     return found;
5025 }
5026 
5027 int match_nrflag2(firmware *fw, int k, int v)
5028 {
5029     // Found NR_GetDarkSubType function, now follow first BL call.
5030     if (isBL(fw,k))
5031     {
5032         k = idxFollowBranch(fw,k,0x01000001);
5033         return search_fw(fw, match_nrflag3, k, 0, 1);
5034     }
5035 
5036     return 0;
5037 }
5038 
5039 // find LEDs, Vx specific
5040 
5041 // ADD Rx, Rx, #0x220000
5042 int isADD_0x220000(firmware *fw, int offset)
5043 {
5044     return ((fwval(fw,offset) & 0xfff00fff) == (0xe2800822));
5045 }
5046 
5047 typedef struct {
5048     uint32_t addr;  // LED GPIO address
5049     int reg;        // register used to assemble the address
5050     int offs;       // offset in the LED table
5051 } LED_s;
5052 
5053 int find_leds(firmware *fw)
5054 {
5055     int j1, j2, m, n;
5056     LED_s led;
5057     int k1 = find_str_ref(fw,"LEDCon");
5058     if (k1<0)
5059         return 0;
5060     k1 = find_inst_rev(fw,isSTMFD_LR,k1,96);
5061     if (k1<0)
5062         return 0;
5063     j1 = find_inst(fw,isBL,k1,80);
5064     j2 = find_Nth_inst(fw,isBL,k1,80,3);
5065     if ((j1<0) || (j2<0))
5066         return 0;
5067     // 1st and 3rd BL is memory allocation
5068     if (followBranch(fw,idx2adr(fw,j1),0x01000001) != followBranch(fw,idx2adr(fw,j2),0x01000001))
5069         return 0;
5070     k1 = find_Nth_inst(fw,isBL,k1,80,2);
5071     // LED table initializer func
5072     k1 = idxFollowBranch(fw,k1,0x01000001);
5073     if (k1<0)
5074         return 0;
5075     bprintf("// LED table init @ 0x%x\n",idx2adr(fw,k1));
5076     j2 = 1;
5077     while (1)
5078     {
5079         j1 = find_Nth_inst(fw,isADD_0x220000,k1,40,j2);
5080         if (j1>0)
5081         {
5082             led.reg = fwRd(fw,j1);
5083             led.addr = 0x220000;
5084             led.offs = 0;
5085             n = j1-1;
5086             while (!isSTMFD_LR(fw,n))
5087             {
5088                 if ((fwval(fw,n)&0xfffff000) == (0xe2800000+(led.reg<<12)+(led.reg<<16))) // ADD Rx, Rx, #0xc00000yz
5089                 {
5090                     if ( ALUop2a(fw,n) >= 0xc0000000 )
5091                     {
5092                         led.addr += ALUop2a(fw,n);
5093                     }
5094                 }
5095                 else if ((fwval(fw,n)&0xfffff000) == (0xe3a00000+(led.reg<<12))) // MOV Rx, #imm
5096                 {
5097                     led.addr += ALUop2a(fw,n);
5098                     m = n+1;
5099                     while (!isLDMFD_PC(fw,m))
5100                     {
5101                         if ((fwval(fw,m)&0xfff0f000) == (0xe5800000+(led.reg<<12))) // STR Rx, [Ry, imm]
5102                         {
5103                             led.offs = fwval(fw,m) & 0xfff;
5104                             break;
5105                         }
5106                         m++;
5107                     }
5108                     if (led.offs != 0)
5109                         break;
5110                 }
5111                 n--;
5112             }
5113             // output data if valid
5114             if (led.offs != 0)
5115             {
5116                 bprintf("// LED #%i: 0x%08x, offset 0x%x\n",j2, led.addr, led.offs);
5117             }
5118             j2++;
5119         }
5120         else
5121         {
5122             break;
5123         }
5124     }
5125     bprintf("\n");
5126     return 0;
5127 }
5128 
5129 // Search for things
5130 void find_other_vals(firmware *fw)
5131 {
5132     out_hdr = 1;
5133     add_blankline();
5134 
5135     bprintf("// Misc stuff\n");
5136     add_blankline();
5137     print_exmem_types(fw);
5138     find_leds(fw);
5139 
5140     // Look for nrflag (for capt_seq.c)
5141     search_saved_sig(fw, "NR_GetDarkSubType", match_nrflag2, 0, 0, 20);
5142 }
5143 
5144 //------------------------------------------------------------------------------------------------------------
5145 
5146 void print_kval(firmware *fw, uint32_t tadr, int tsiz, int tlen, uint32_t ev, const char *name, char *sfx)
5147 {
5148     int tidx = adr2idx(fw,tadr);
5149     int k, kval = 0;
5150     for (k=0; k<tlen; k+=tsiz)
5151     {
5152         if (fw->buf[tidx+k+1] == ev)
5153         {
5154             kval = fw->buf[tidx+k];
5155             tadr = idx2adr(fw,tidx+k);
5156             break;
5157         }
5158     }
5159     if (kval > 0)
5160     {
5161         char fn[100], rn[100];
5162         strcpy(fn,name); strcat(fn,sfx);
5163         strcpy(rn,name); strcat(rn,"_IDX");
5164 
5165         int r = (kval >> 5) & 7;
5166         uint32_t b = (1 << (kval & 0x1F));
5167 
5168         bprintf("//#define %-20s0x%08x // Found @0x%08x, levent 0x%x\n",fn,b,tadr,ev);
5169         bprintf("//#define %-20s%d\n",rn,r);
5170     }
5171 }
5172 
5173 typedef struct {
5174     int         reg;
5175     uint32_t    bits;
5176     char        nm[32];
5177     uint32_t    fadr;
5178     uint32_t    ev;
5179     int         inv;
5180 } kinfo;
5181 
5182 int     kmask[3];
5183 kinfo   key_info[100];
5184 int     kcount = 0;
5185 uint32_t kshutter_min_bits = 0xFFFFFFFF;
5186 
5187 void add_kinfo(int r, uint32_t b, const char *nm, uint32_t adr, uint32_t ev, int inv)
5188 {
5189     key_info[kcount].reg = r;
5190     key_info[kcount].bits = b;
5191     strcpy(key_info[kcount].nm, nm);
5192     key_info[kcount].fadr = adr;
5193     key_info[kcount].ev = ev;
5194     key_info[kcount].inv = inv;
5195     kcount++;
5196     kmask[r] |= b;
5197     if ((ev <= 1) && (b < kshutter_min_bits)) kshutter_min_bits = b;
5198 }
5199 
5200 uint32_t add_kmval(firmware *fw, uint32_t tadr, int tsiz, int tlen, uint32_t ev, const char *name, uint32_t xtra)
5201 {
5202     int tidx = adr2idx(fw,tadr);
5203     int r, k, kval = 0;
5204     uint32_t b = 0;
5205     int inv = 0;
5206     for (k=0; k<tlen; k+=tsiz)
5207     {
5208         if (fw->buf[tidx+k+1] == ev)
5209         {
5210             kval = fw->buf[tidx+k];
5211             tadr = idx2adr(fw,tidx+k);
5212             break;
5213         }
5214     }
5215     if (kval > 0)
5216     {
5217         r = (kval >> 5) & 7;
5218         b = (1 << (kval & 0x1F));
5219         inv = ((kval&0xff0000)==0x10000)?0:1;
5220 
5221         add_kinfo(r,b|xtra,name,tadr,ev,inv);
5222     }
5223 
5224     return b;
5225 }
5226 
5227 int kinfo_compare(const kinfo *p1, const kinfo *p2)
5228 {
5229     if (p1->reg > p2->reg)
5230     {
5231         return 1;
5232     }
5233     else if (p1->reg < p2->reg)
5234     {
5235         return -1;
5236     }
5237     if ((p1->ev <= 1) && (p2->ev <= 1))    // output shutter entries in reverse order
5238     {
5239         if (p1->bits > p2->bits)
5240         {
5241             return -1;
5242         }
5243         else if (p1->bits < p2->bits)
5244         {
5245             return 1;
5246         }
5247     }
5248     // if one entry is shutter then compare to min shutter bits
5249     if (p1->ev <= 1)
5250     {
5251         if (kshutter_min_bits > p2->bits)
5252         {
5253             return 1;
5254         }
5255         else if (kshutter_min_bits < p2->bits)
5256         {
5257             return -1;
5258         }
5259     }
5260     if (p2->ev <= 1)
5261     {
5262         if (p1->bits > kshutter_min_bits)
5263         {
5264             return 1;
5265         }
5266         else if (p1->bits < kshutter_min_bits)
5267         {
5268             return -1;
5269         }
5270     }
5271     if (p1->bits > p2->bits)
5272     {
5273         return 1;
5274     }
5275     else if (p1->bits < p2->bits)
5276     {
5277         return -1;
5278     }
5279 
5280     return 0;
5281 }
5282 
5283 void print_kmvals()
5284 {
5285     qsort(key_info, kcount, sizeof(kinfo), (void*)kinfo_compare);
5286 
5287     bprintf("//static KeyMap keymap[] = {\n");
5288 
5289     int k;
5290     for (k=0; k<kcount; k++)
5291     {
5292         bprintf("//    { %d, %-20s,0x%08x }, // Found @0x%08x, levent 0x%02x%s\n",key_info[k].reg,key_info[k].nm,key_info[k].bits,key_info[k].fadr,key_info[k].ev,(key_info[k].inv==0)?"":" (uses inverted logic in physw_status)");
5293     }
5294 
5295     bprintf("//    { 0, 0, 0 }\n//};\n");
5296 }
5297 
5298 int match_GetSDProtect(firmware *fw, int k, int v)
5299 {
5300     if (isB(fw,k))    // B
5301     {
5302         k = idxFollowBranch(fw,k,1);
5303         if (isLDR_PC(fw,k))
5304         {
5305             return LDR2val(fw,k);
5306         }
5307     }
5308 
5309     return 0;
5310 }
5311 
5312 void find_key_vals(firmware *fw)
5313 {
5314     int k,k1;
5315 
5316     out_hdr = 1;
5317     add_blankline();
5318 
5319     // find 'SD_READONLY_FLAG'
5320     uint32_t tadr = search_saved_sig(fw, "GetSDProtect", match_GetSDProtect, 0, 1, 1);
5321     if (tadr == 0)
5322     {
5323         k = find_str_ref(fw,"SD Not Exist\n");
5324         if (k >= 0)
5325         {
5326             for (k1=k-1; k1>k-5; k1--)
5327             {
5328                 if (isBL(fw,k1))    // BL
5329                 {
5330                     uint32_t fadr = followBranch(fw,idx2adr(fw,k1),0x01000001);
5331                     int k2 = adr2idx(fw,fadr);
5332                     if (isLDR_PC(fw,k2))
5333                     {
5334                         tadr = LDR2val(fw,k2);
5335                     }
5336                 }
5337             }
5338         }
5339     }
5340     if (tadr != 0)
5341     {
5342         int tsiz = 2;
5343         if (fw->buf[adr2idx(fw,tadr)+2] == 0) tsiz = 3;
5344 
5345         uint32_t madr = fw->base + (fw->size*4-4);
5346         for (k=0; k<(tadr-fw->base)/4; k++)
5347         {
5348             if (isLDR_PC(fw,k))
5349             {
5350                 uint32_t adr = LDR2val(fw,k);
5351                 if ((adr > tadr) && (adr < madr))
5352                 {
5353                     madr = adr;
5354                 }
5355             }
5356         }
5357         int tlen = (madr - tadr) / 4;
5358         if (tsiz == 2)
5359         {
5360             k1 = adr2idx(fw,tadr);
5361             for (k=0; k<tlen/3; k+=3)
5362             {
5363                 if ((fw->buf[k1+k+1] == 0xFFFFFFFF) && (fw->buf[k1+k+4] == 0xFFFFFFFF))
5364                 {
5365                     tsiz = 3;
5366                     break;
5367                 }
5368             }
5369         }
5370         if (tlen > 50*tsiz) tlen = 50*tsiz;
5371 
5372         bprintf("// Bitmap masks and physw_status index values for SD_READONLY and USB power flags (for kbd.c).\n");
5373         if (fw->dryos_ver >= 49)
5374         {
5375             // Event ID's have changed in DryOS R49 **********
5376             print_kval(fw,tadr,tsiz,tlen,0x20A,"SD_READONLY","_FLAG");
5377             print_kval(fw,tadr,tsiz,tlen,0x202,"USB","_MASK");
5378         }
5379         else
5380         {
5381             print_kval(fw,tadr,tsiz,tlen,0x90A,"SD_READONLY","_FLAG");
5382             print_kval(fw,tadr,tsiz,tlen,0x902,"USB","_MASK");
5383         }
5384 
5385         uint32_t key_half = add_kmval(fw,tadr,tsiz,tlen,0,"KEY_SHOOT_HALF",0);
5386         add_kmval(fw,tadr,tsiz,tlen,1,"KEY_SHOOT_FULL",key_half);
5387         add_kmval(fw,tadr,tsiz,tlen,1,"KEY_SHOOT_FULL_ONLY",0);
5388         add_kmval(fw,tadr,tsiz,tlen,2,"KEY_ZOOM_IN",0);
5389         add_kmval(fw,tadr,tsiz,tlen,3,"KEY_ZOOM_OUT",0);
5390         add_kmval(fw,tadr,tsiz,tlen,4,"KEY_UP",0);
5391         add_kmval(fw,tadr,tsiz,tlen,5,"KEY_DOWN",0);
5392         add_kmval(fw,tadr,tsiz,tlen,6,"KEY_LEFT",0);
5393         add_kmval(fw,tadr,tsiz,tlen,7,"KEY_RIGHT",0);
5394         add_kmval(fw,tadr,tsiz,tlen,8,"KEY_SET",0);
5395         add_kmval(fw,tadr,tsiz,tlen,9,"KEY_MENU",0);
5396         add_kmval(fw,tadr,tsiz,tlen,0xA,"KEY_DISPLAY",0);
5397         if (fw->dryos_ver <= 47)
5398         {
5399             add_kmval(fw,tadr,tsiz,tlen,0x601,"KEY_PLAYBACK",0);
5400             add_kmval(fw,tadr,tsiz,tlen,0x600,"KEY_POWER",0);
5401             add_kmval(fw,tadr,tsiz,tlen,0x12,"KEY_VIDEO",0);
5402         }
5403         else
5404         {
5405             add_kmval(fw,tadr,tsiz,tlen,0x101,"KEY_PLAYBACK",0);
5406             add_kmval(fw,tadr,tsiz,tlen,0x100,"KEY_POWER",0);
5407             if (fw->dryos_ver == 49)
5408             {
5409                 add_kmval(fw,tadr,tsiz,tlen,0x19,"KEY_VIDEO",0);
5410             }
5411             else if(fw->dryos_ver == 50)
5412             {
5413                 add_kmval(fw,tadr,tsiz,tlen,0x1A,"KEY_VIDEO",0);
5414                 add_kmval(fw,tadr,tsiz,tlen,0x14,"KEY_HELP",0);
5415             }
5416         }
5417 
5418         bprintf("\n// Keymap values for kbd.c. Additional keys may be present, only common values included here.\n");
5419         print_kmvals();
5420     }
5421 }
5422 
5423 //------------------------------------------------------------------------------------------------------------
5424 
5425 uint32_t nadr;
5426 uint32_t eadr;
5427 
5428 int get_eventproc_val(firmware *fw, int k)
5429 {
5430     if (isADR_PC(fw,k) && (fwRd(fw,k) == 0))
5431         nadr = ADR2adr(fw,k);
5432     else if (isADR_PC(fw,k) && (fwRd(fw,k) == 1))
5433         eadr = ADR2adr(fw,k);
5434     else if (isLDR_PC(fw,k) && (fwRd(fw,k) == 0))
5435         nadr = LDR2val(fw,k);
5436     else if (isLDR_PC(fw,k) && (fwRd(fw,k) == 1))
5437         eadr = LDR2val(fw,k);
5438     else
5439         return 0;
5440     return 1;
5441 }
5442 
5443 void add_func_name(char *n, uint32_t eadr, char *suffix)
5444 {
5445     int k;
5446 
5447     char *s = n;
5448     if (suffix != 0)
5449     {
5450         s = malloc(strlen(n) + strlen(suffix) + 1);
5451         sprintf(s, "%s%s", n, suffix);
5452     }
5453 
5454     for (k=0; func_names[k].name != 0; k++)
5455         if (strcmp(func_names[k].name, s) == 0)
5456         {
5457             if (func_names[k].val == 0)
5458             {
5459                 func_names[k].val = eadr;
5460                 func_names[k].flags |= EV_MATCH;
5461             }
5462             if (s != n) free(s);
5463             return;
5464         }
5465 
5466     func_names[next_func_entry].name = s;
5467     func_names[next_func_entry].flags = OPTIONAL|UNUSED;
5468     func_names[next_func_entry].val = eadr;
5469     next_func_entry++;
5470     func_names[next_func_entry].name = 0;
5471 }
5472 
5473 void add_func_name2(firmware *fw, uint32_t nadr, uint32_t eadr, char *suffix)
5474 {
5475     char *n = (char*)adr2ptr(fw,nadr);
5476     if (*n)
5477     {
5478         if (isB(fw,adr2idx(fw,eadr)))
5479         {
5480             char *s = malloc(strlen(n) + 3);
5481             sprintf(s,"j_%s",n);
5482             add_func_name(s, eadr, suffix);
5483             eadr = followBranch(fw,eadr,1);
5484         }
5485         add_func_name(n, eadr, suffix);
5486     }
5487 }
5488 
5489 int match_eventproc(