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