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