txt2h.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. #!/usr/bin/php
  2. <?php
  3. /*
  4. * Copyright (C) 2017 bzt (bztsrc@gitlab)
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. *
  20. * @brief Quick and really dirty tool to generate C code from the instruction table in
  21. * the txt file. Don't try to understand this code, specially if your IQ is under 140!
  22. * Wild array indexing, php hacks and regular expressions ahead! You have been warned!
  23. */
  24. function sh($a,$s,$n,&$sho) { $l=count($a);foreach($a as $k=>$A) @$b[$A-($l-$k-1)]|=1<<($l-$k-1);$c=($s?"((ic".$n.(isset($sho[$n."_".$a[0]])?"_".$a[0]:($a[0]?">>".$a[0]:"")).
  25. ")&1?(0xffffffff<<".$l."):0)":"");foreach($b as $k=>$b) $c.=($c?"|":"")."((ic".$n.(isset($sho[$n."_".$k])?"_".$k:($k?">>".$k:"")).")&0x".dechex($b).")";return $c;}
  26. function b2h($b) { return base_convert($b,2,16); }
  27. $pre="disasm"; $copy=[]; $argdefc=[]; $argdef=[]; $in=[]; $out=[]; $list=['signext'=>['i','a0','a1']]; $mn=[]; $ar=[];
  28. $fn=@$_SERVER['argv'][1]; $hv=@$_SERVER['argv'][2]=='-v'; $ha=@$_SERVER['argv'][2]=='-a'; $hi=$_SERVER['argc']>2&&!$hv&&!$ha; $hn=@$_SERVER['argv'][3]=="-n"; $hs=$_SERVER['argc']>3&&!$hn;
  29. if(empty($fn)) die("Universal Disassember by bzt\n\n".$_SERVER['argv'][0]." <text file> [-v|-i|-a] [-s|-n]\n\n text file\t- an ascii text file with instruction table definitions\n -v\t\t- optional verbose flag, report unused definitions\n -i\t\t- add external variables for integration\n -a\t\t- code analysis report on instruction\n -s\t\t- sprintf returns char*\n -n\t\t- use snprintf with the additional size argument\n\nQuick and dirty script to convert ascii instruction table into a C header.\n");
  30. $data=str_replace("\r","",@file_get_contents($fn));preg_match_all("/\/\*.*?\*\//sm", $data, $m);
  31. if(!empty($m) && !empty($m[0])) foreach($m[0] as $c) $data=str_replace($c,str_repeat("\n",substr_count($c,"\n")),$data); $data=explode("\n",$data);
  32. if(!is_array($data) || empty($data)) { echo("ERROR: unable to read file ".$fn."\n"); $data=[]; }
  33. $var['op']=15; if(!$ha)$var['om']=15; $nop=""; $il=$am=$hp=$hd=$hb=0; $is=[];
  34. $Is=[1=>8,2=>16,3=>32,4=>32,5=>64,6=>64,7=>64,8=>64];
  35. foreach($data as $L=>$line) {
  36. $line=trim($line);
  37. if(empty($line) || $line[0]=='/') continue;
  38. if($line[0]=='+') { $copy[]=substr($line,1); continue; }
  39. $rows=explode("\t",$line);
  40. $rows[0]=str_replace("{","",$rows[0]);
  41. if($rows[0][0]=='<') {
  42. $d=str_replace("}","_opt",str_replace(">","",substr($rows[0],1)));
  43. if(preg_match("/[^a-zA-Z0-9_]/",$d)) { echo("ERROR: not a valid argument name '".$rows[0]."' in line ".($L+1)."\n"); continue; }
  44. if(isset($argdef[$d]))
  45. echo("ERROR: argument type ".$rows[0]." redefined in line ".($L+1)."\n");
  46. $argdef[$d]=$rows[1]; if(strpos($rows[1],'^')!==false) $hb=1;
  47. $T=preg_replace("/[^a-zA-Z]/","", preg_replace("/[\"']([^'\"]*)[\"']/","",preg_replace("/[\@\'a-zA-Z][a-zA-Z0-9_]+/","",$rows[1])));
  48. unset($t); for($i=0;$i<strlen($T);$i++) $t[$T[$i]]=1;
  49. preg_match_all("/[^a-zA-Z0-9](a[0-9]+)[^a-zA-Z0-9]/"," ".$rows[1]." ",$m);
  50. if(!empty($m[1])) foreach($m[1] as $k=>$v) $t[$v]=1;
  51. $argdeft[$d]=!empty($t)?array_keys($t):[];
  52. continue;
  53. }
  54. if($rows[0]=="@disasm") { $pre=trim($rows[1]); continue; }
  55. if($rows[0][0]=='@') { if(isset($list[substr($rows[0],1)])&&substr($rows[0],1)!="signext") echo("ERROR: list ".$rows[0]." redefined in line ".($L+1)."\n");
  56. $list[substr($rows[0],1)]=explode(" ",strtolower(trim(@$rows[1]))); continue; }
  57. if(empty($rows[1]) && substr($rows[0],-1)!='+') { echo("ERROR: missing mnemonics in line ".($L+1)."\n"); continue; }
  58. $bp=explode("+",$rows[0]);
  59. if(empty($Is[strlen($bp[0])/8])) { echo("ERROR: bad bitmask length in line ".($L+1)."\n"); continue; }
  60. if(preg_match("/[^a-zA-Z01]/",$bp[0])) { echo("ERROR: invalid character in bitmask in line ".($L+1)."\n"); continue; }
  61. $bm=preg_replace("/[^01]/","x",$bp[0]);
  62. if(empty($in[$bm])) $in[$bm]=(object)[];
  63. $in[$bm]->l[]=$L+1;
  64. $in[$bm]->c=$bp[0];
  65. if(strpos($rows[1],"<c>")) { $listc["conds"]=1; $argdefc["c"]=1; }
  66. $in[$bm]->i=str_replace("<c>","%s",strtolower($rows[1]));
  67. $in[$bm]->p=isset($bp[1])&&(empty($bp[1])||$bp[1]==""); if($in[$bm]->p) $hp=1;
  68. $p=strtolower(str_replace("0","",str_replace("1","",str_replace("x","",$bp[0]))));
  69. unset($d); for($i=0;$i<strlen($p);$i++) @$d[$p[$i]]++;
  70. if(!empty($d)) foreach($d as $b=>$v) if(@$var[$b]<$v) $var[$b]=$v;
  71. if(!empty($rows[3])) {
  72. $in[$bm]->e=trim($rows[3]); preg_match_all("/([^=;]+)=([^=;]+)/",$in[$bm]->e,$m);
  73. if(!empty($m)&&!empty($m[1]))
  74. foreach($m[1] as $k=>$v) { $v=trim($v); @$d[$v]++; if(!isset($var[$v]) && !empty($m[2][$k])) {if(strpos($m[2][$k],"\"")!==false) $varc[$v]=1; else $var[$v]=8; } }
  75. }
  76. if(!empty($bp[1])&&$bp[1]!="") { $in[$bm]->d=explode(",",$bp[1]); $hd=1; foreach($in[$bm]->d as $i)
  77. if(preg_match("/a([0-9]+)/",$i,$m)){
  78. if(intval($m[1])>=count($in[$bm]->d)) echo("WARNING: opcode argument 'a".$m[1]."' required by another argument not defined in line ".($L+1)."\n");
  79. else $ar["a".$m[1]]=1;
  80. }elseif($hv&&preg_match("/^[a-zA-Z][^0-9]/",$i)&&empty($d[$i[0]]))
  81. echo("WARNING: bits '".$i[0]."' required by opcode argument not defined in bitmask in line ".($L+1)."\n");
  82. }
  83. $in[$bm]->a=[]; $c=[];
  84. if(!empty($rows[2])){
  85. foreach(explode(",",preg_replace("/^,/","",preg_replace("/,$/","",str_replace(",,offs",",offs",str_replace("offs,,","offs,",
  86. str_replace(",,offe",",offe",str_replace("offe,,","offe,",str_replace(">","",str_replace("}","_opt",
  87. str_replace("{","",str_replace(" ","",str_replace("[",isset($argdef["offs"])?",offs,":"",
  88. str_replace("]",isset($argdef["offe"])?",offe,":"",$rows[2]))))))))))))) as $a) {
  89. $a=preg_replace("/^[^<]*</","",$a);
  90. if(empty($a) || trim($a)=="") { unset($in[$bm]); echo("ERROR: mailformed argument list in line ".($L+1)."\n"); continue; }
  91. $b=str_replace("_opt","",$a);
  92. if(empty($argdef[$a])) { unset($in[$bm]); echo("ERROR: undefined argument ".($a!=$b?"{":"")."<".
  93. str_replace("_opt","",$a).">".($a!=$b?"}":"")." in line ".($L+1)."\n"); continue; }
  94. if(!empty($argdeft[$a])) {
  95. for($i=0;$i<count($argdeft[$a]);$i++) { $c[$argdeft[$a][$i]]=1;
  96. if(preg_match("/^a[0-9]+$/",$argdeft[$a][$i])) {
  97. $ar[$argdeft[$a][$i]]=1; if(intval(substr($argdeft[$a][$i],1))>=count($in[$bm]->d))
  98. echo("WARNING: opcode argument '".$argdeft[$a][$i]."' required by <".str_replace("_opt","",$a)."> not defined in line ".($L+1)."\n");
  99. }elseif(empty($d[$argdeft[$a][$i]])&&$a!="offs"&&$a!="offe"&&$hv)
  100. echo("WARNING: bits '".$argdeft[$a][$i]."' required by <".str_replace("_opt","",$a)."> not defined in bitmask in line ".($L+1)."\n");
  101. }
  102. }
  103. $argdefc[$a]=1; $in[$bm]->a[]=$a;
  104. }
  105. }
  106. if(!empty($in[$bm]->d)&&$hv){ $e=[]; $f=" ".implode(" ",$in[$bm]->d)." ";for($i=0;$i<count($in[$bm]->d);$i++) if(empty($c["a".$i])&&!preg_match("/[^a-z]a".$i."[^a-z0-9]/",$f)) $e[]="a".$i;
  107. if(!empty($e))echo("WARNING: opcode argument(s) '".implode("','",$e)."' defined but not referenced in line ".($L+1)."\n");}
  108. if(!empty($d)&&$hv) {$e=[]; unset($d['c']); foreach($d as $k=>$v) if(empty($c[$k])) $e[]=$k;
  109. if(!empty($e))echo("WARNING: bit(s) '".implode("','",$e)."' defined but not referenced in line ".($L+1)."\n");}
  110. if(count($in[$bm]->a)>$am) $am=count($in[$bm]->a);
  111. }
  112. foreach($in as $c=>$l) { if(count($l->l)>1) die("CRIT: ambiguous bitmasks ".$c." in lines ".implode(", ",$l->l)."\n"); }
  113. if($hv) foreach($argdef as $k=>$v) if(empty($argdefc[$k])) echo("WARNING: unreferenced argument type <".$k.">\n");
  114. foreach($argdefc as $k=>$v) { preg_match_all("/@([^\[]+)/",$argdef[$k],$m); if(!empty($m)&&!empty($m[1])) { foreach($m[1] as $M) {
  115. if(empty($list[$M])) die("ERROR: undefined list @".$M." in <".str_replace("_opt","",$k).">\n"); $listc[$M]=1; } } }
  116. $listc['signext']=1; if($hv) foreach($list as $k=>$v) if(empty($listc[$k])) echo("WARNING: unreferenced list @".$k."\n");
  117. $r=[]; foreach($in as $k=>$o) { $d=$o->p."|".(!empty($o->d)?@implode(",",$o->d):"")."|".@$o->e."|".($o->i=="nop"?"1":"0")."|"; if(!empty($o->a)) foreach($o->a as $a) $d.=$a."|"; $r[$d][]=$o->c; }
  118. foreach($r as $v) { sort($v); unset($V); foreach($v as $i) $V[preg_replace("/[01]/","}",$i)][]=$i; foreach($V as $k=>$v) { $s=0;
  119. do{
  120. $e=count($v); do { $c=[]; for($i=0;$i<strlen($k);$i++) { if($k[$i]!='}') continue; $c[$i]=[0,0]; for($j=$s;$j<$e;$j++) $c[$i][intval($v[$j][$i])]++; } $d=0; foreach($c as $a) if($a[0]!=0&&$a[1]!=0) $d++; $e--; } while($e>$s && pow(2,ceil(log($e-$s)/log(2))+1)<(1<<$d)); $e++;
  121. $g=array_slice($v,$s,$e-$s);
  122. $c=[]; for($i=0;$i<strlen($k);$i++) { if($k[$i]!='}') continue; $c[$i]=[0,0]; for($j=$s;$j<$e;$j++) $c[$i][intval($v[$j][$i])]++; }
  123. $d=""; $b=0; for($i=0;$i<strlen($k);$i++) { if($k[$i]!='}') { $d.=$k[$i]; continue; } $c=[0,0];
  124. for($j=$s;$j<$e;$j++) $c[intval($v[$j][$i])]++; $d.=$c[0]==0?'1':($c[1]==0?'0':'~'); if($c[0]!=0&&$c[1]!=0) $b++; }
  125. $o=preg_replace("/[^01]/","x",$g[0]); $n=preg_replace("/[^01]/","x",$d);
  126. if(isset($out[$n])) die("CRIT: conflicting bitmask ".$d."\n"); if(empty($out[$n])) $out[$n]=(object)[]; @$out[$n]->bm=$d; $out[$n]->c=str_replace("x","0",$n);
  127. $out[$n]->m=str_replace("x","0",str_replace("0","1",$n)); $out[$n]->s=strlen($d); $is[$out[$n]->s]=$out[$n]->s/8; $out[$n]->i=[];
  128. for($i=0;$i<strlen($d);$i++) if($d[$i]!='X'&&preg_match("/[A-Z~]/",$d[$i])) $out[$n]->b[$d[$i]!='~'?strtolower($d[$i]):"op"][]=(strlen($n)-1-$i);
  129. for($i=0;$i<strlen($d);$i++) if($d[$i]!='x'&&preg_match("/[a-z]/",$d[$i])) $out[$n]->b[$d[$i]][]=(strlen($n)-1-$i);
  130. foreach(['p','d','e','a'] as $a) if(isset($in[$o]->$a)) $out[$n]->$a=$in[$o]->$a;
  131. for($i=0;$i<pow(2,$b);$i++) {
  132. $a=$b-1;$c="";for($j=0;$j<strlen($d);$j++) if($d[$j]=='~') { $c.=($i&(1<<$a)?'1':'0'); $a--; } else $c.=$d[$j];
  133. @$m=$in[preg_replace("/[^01]/","x",$c)]->i; if($m) { if($m=="nop") $nop=$n; $mn[$m]=1; if(strlen($m)>$il) $il=strlen($m); }
  134. $out[$n]->i[]=$m?$m:"?";
  135. }
  136. for($i=count($out[$n]->i)-1;$i>0;$i--) if($out[$n]->i[$i]=="?") unset($out[$n]->i[$i]); else break;
  137. $s=$e;
  138. } while($s<count($v));
  139. }
  140. }
  141. ksort($out,SORT_STRING);
  142. echo("STAT: Lists: ".count($list).", Argument types: ".count($argdefc).", Longest mnemonic: ".$il.", Max arguments: ".$am."\n");
  143. echo("STAT: Mnemonics: ".count($mn).", Instruction groups: ".count($out).", Instructions: ".count($in)."\n");
  144. if($il<7) $il=7; if(empty($is)) $is[8]=1;
  145. foreach($var as $k=>$v) { if($v<=8) $var[$k]=8; else if($v<=16) $var[$k]=16; else if($var[$k]<=32) $var[$k]=32; else $var[$k]=64; }
  146. $sho=[];
  147. foreach($out as $k=>$o) {
  148. if(!empty($o->b)) foreach($o->b as $g=>$b) {
  149. $c=[];$l=count($b);foreach($b as $K=>$A) @$c[$A-($l-$K-1)]|=1<<($l-$K-1);
  150. foreach($c as $v=>$b) if($v) @$sho[$o->s."_".$v]++;
  151. }
  152. if(str_replace("0","",$o->m)==$o->m && $Is[$o->s/8]==strlen($o->m)) continue;
  153. $w=0; foreach([24,16,8] as $i) if(substr($o->m,-$i)==str_repeat("0",$i)) { $w=$i;break; }
  154. if($w>0) @$sho[$o->s."_".$w]++;
  155. }
  156. foreach($sho as $k=>$v) if($v<3) unset($sho[$k]);
  157. $c="/* Universal Disassembler Function Library\n * https://gitlab.com/bztsrc/udisasm\n *\n * ----- GENERATED FILE, DO NOT EDIT! -----\n *\n * Copyright (C) 2017 bzt (bztsrc@gitlab)
  158. *
  159. * Permission is hereby granted, free of charge, to any person
  160. * obtaining a copy of this software and associated documentation
  161. * files (the \"Software\"), to deal in the Software without
  162. * restriction, including without limitation the rights to use, copy,
  163. * modify, merge, publish, distribute, sublicense, and/or sell copies
  164. * of the Software, and to permit persons to whom the Software is
  165. * furnished to do so, subject to the following conditions:
  166. *
  167. * The above copyright notice and this permission notice shall be
  168. * included in all copies or substantial portions of the Software.
  169. *
  170. * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,
  171. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  172. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  173. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  174. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  175. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  176. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  177. * DEALINGS IN THE SOFTWARE.
  178. *
  179. * @brief Disassembler source generated from ".$fn."
  180. */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
  181. $c.="#define ".$pre."_arch \"".explode(".",$fn)[0]."\"\n";
  182. if($hn) $c.="#define ".$pre."_snprintf 1\n";
  183. if($ha) $c.="#define ".$pre."_analytics 1\n";
  184. if($hi) $c.="#define ".$pre."_integration 1\nextern uint8_t sys_fault;\nextern uint64_t dbg_label, buf_reloc;\n";
  185. $c.="enum { ".$pre."_arg_NONE,".$pre."_arg_ofs,".$pre."_arg_ofe"; foreach($argdefc as $k=>$v) $c.=", ".$pre."_arg_".$k; $c.=" };\n";
  186. $c.="\n/*** private functions ***/\n";
  187. $c.="char *".$pre."_str(char*s,int n) {";
  188. //due to a gcc optimizer bug when compiling to Aarch64, we have to remove the extra checks... F*ck
  189. //$c.="while(s&&*((uint16_t*)s)&&n){s++;if(!*s){s++;n--;}}return s&&*s?s:\"?\";";
  190. $c.="if(!s)return \"?\";while(n){s++;if(!*s){s++;n--;}}return *s?s:\"?\";";
  191. $c.="}\n";foreach($copy as $C) $c.=str_replace("disasm_",$pre."_",$C)."\n";
  192. $c.="\n/*** public API ***/\nuint64_t ".$pre."(uint64_t addr, char *str".($hn?", int size":"").")\n{\n";
  193. foreach([64,32,16,8] as $i) {
  194. $o=0;foreach($var as $k=>$v)if($v==$i){$o=1;break;}if(!$o)continue;
  195. $c.=" uint".$i."_t "; $f=1; foreach($var as $k=>$v) { if($v==$i) { if($f) $f=0; else $c.=", "; $c.=$k."=0";} }
  196. $c.=";\n";
  197. }
  198. if($hd) $c.=" int64_t ".implode(", ",array_keys($ar)).";\n";
  199. foreach($is as $i=>$v) {
  200. $c.=" uint".($Is[$i/8])."_t ic".$i;
  201. foreach($sho as $j=>$v) if(explode("_",$j)[0]==$i) $c.=", ic".$j;
  202. $c.=";\n";
  203. }
  204. if($ha) $c.=" uint64_t oaddr=addr;\n uint8_t ai;\n";
  205. if($hp||$hb) $c.=" uint64_t iaddr=addr".($hi?"-buf_reloc":"").";\n";
  206. $c.=" char *names=NULL".($ha?",psb[256],*ps=(char*)&psb":",*olds=str").($hn?",*ends=str+size-".($ha?"5":"3"):"");
  207. if(!empty($varc)) foreach($varc as $k=>$v) $c.=",*".$k."=NULL"; $c.=";\n";
  208. foreach($list as $k=>$v) if($k!="disasm"&&$k!="signext") { $c.=" char *".$k."=\""; foreach($v as $t) $c.=$t."\\0"; $c.="\";\n"; }
  209. $c.=" uint8_t args[".($am+1)."]={0".str_repeat(",0",$am)."};\n\n";
  210. if($hp) $c.="getopcode:\n";
  211. if($hi) $c.=" dbg_label=0; sys_fault=0;\n";
  212. foreach($is as $i=>$v)
  213. $c.=" ic".$i."=*((uint".($Is[$i/8])."_t*)addr);\n";
  214. if(!empty($sho)){$c.=" ";foreach($sho as $i=>$v) $c.=" ic".$i."=ic".str_replace("_",">>",$i).";";$c.="\n";}
  215. if($hi) $c.=" if(sys_fault) return addr+1;\n";
  216. if(isset($out[$nop])) {
  217. $c.="\n /* handle multiple NOPs at once */\n if(ic".$out[$nop]->s."==0x".b2h($out[$nop]->c).
  218. ") {\n while(*((uint".$out[$nop]->s."_t*)addr)==ic".$out[$nop]->s.") { op++; addr+=".($out[$nop]->s/8)."; }\n".
  219. " if(str!=NULL) ";
  220. if($ha) {
  221. $c.="str".($hs?"":"+")."=s".($hn?"n":"")."printf(str,".($hn?"size,":"")."\"{\\\"mask\\\":\\\"".$out[$nop]->bm."\\\",\\\"prefix\\\":[],\\\"instruction\\\":[";
  222. $d=dechex(bindec($out[$nop]->c)); for($i=strlen($d)-2;$i>=0;$i-=2) $c.="0x".substr($d,$i,2).($i?", ":"");
  223. $c.="],\\\"count\\\":%d,\\\"bitgroups\\\":{},\\\"arguments\\\":[],\\\"prefixstr\\\":\\\"\\\",\\\"decoded\\\":\\\"nop\\\"}\",op);";
  224. } else
  225. $c.="str".($hs?"":"+")."=s".($hn?"n":"")."printf(str,".($hn?"size,":"")."\" %d x nop\",op);";
  226. $c.="\n *str=0;\n return addr;\n }\n";
  227. }
  228. $c.="\n /* decode instruction */\n"; $e=0;
  229. foreach($out as $k=>$o) {
  230. if($k==$nop) continue;
  231. if($o->m==$o->c&&intval($o->m)==0) { $c.=" "; $e=1; } else {
  232. $c.=" if(";
  233. if(str_replace("0","",$o->m)==$o->m && $Is[$o->s/8]==strlen($o->m)) $c.="ic".$Is[$o->s/8]."==0x".b2h($o->c); else {
  234. $w=0; foreach([24,16,8] as $i) if(substr($o->m,-$i)==str_repeat("0",$i)) { $w=$i;break; }
  235. $c.="(".($w?"(":"")."ic".$o->s.(isset($sho[$o->s."_".$w])?"_".$w.")":($w?">>".$w.")":"")).
  236. "&0x".b2h(substr($o->m,0,strlen($o->m)-$w)).")==0x".b2h(substr($o->c,0,strlen($o->c)-$w));
  237. } $c.=") "; } $c.="{\n";
  238. if(!empty($o->i) && $o->i[0]!="") $c.=" names=\"";foreach($o->i as $i) $c.=$i."\\0";$c.="\";\n";
  239. if(!empty($o->b)) {$c.=" ";foreach($o->b as $k=>$v) {if($hp)$c.=$k."<<=".count($v).";"; $c.=$k."=".sh($v,in_array($k,$list['signext']),$o->s,$sho)."; ";} $c.="\n";}
  240. if(!empty($o->e)) $c.=" ".$o->e.";\n";
  241. if(!empty($o->a)) {$c.=" "; foreach($o->a as $k=>$a) $c.="args[".$k."]=".$pre."_arg_".$a."; ";$c.="\n";}
  242. if($ha && empty($o->p)) {
  243. $c.=" if(str!=NULL) {\n";
  244. $c.=" str".($hs?"":"+")."=s".($hn?"n":"")."printf(str,".($hn?"ends-str,":"")."\"{\\\"mask\\\":\\\"".$o->bm."\\\",\\\"prefix\\\":[\");\n";
  245. $c.=" ai=0;for(;oaddr<addr;oaddr++){str".($hs?"":"+")."=s".($hn?"n":"")."printf(str,".($hn?"ends-str,":"")."\"%s0x%02x\",ai?\", \":\"\", *((uint8_t*)oaddr)); ai=1; }\n";
  246. $c.=" str".($hs?"":"+")."=s".($hn?"n":"")."printf(str,".($hn?"ends-str,":"")."\"],\\\"instruction\\\":[\");\n";
  247. if(count($is)!=1) $c.=" }\n";
  248. }
  249. if(count($is)!=1) $c.=" addr+=".($o->s/8).";\n";
  250. if($ha && empty($o->p)) {
  251. if(count($is)!=1) $c.=" if(str!=NULL) {\n";
  252. $c.=" for(ai=0;ai<".($o->s/8).";ai++) str".($hs?"":"+")."=s".($hn?"n":"")."printf(str,".($hn?"ends-str,":"")."\"%s0x%02x\",ai?\",\":\"\", *((uint8_t*)(oaddr+ai)));\n";
  253. $c.=" str".($hs?"":"+")."=s".($hn?"n":"")."printf(str,".($hn?"ends-str,":"")."\"],\\\"count\\\":1,\\\"bitgroups\\\":{";
  254. if(!empty($o->b)) { $d=0;foreach($o->b as $k=>$v) {$c.=($d?", ":"")."\\\"".($k=="op"?"~":$k)."\\\":%d";$d=1;} $c.="\""; foreach($o->b as $k=>$v) $c.=",".$k; } else $c.="\"";
  255. $c.=");\n str".($hs?"":"+")."=s".($hn?"n":"")."printf(str,".($hn?"ends-str,":"")."\"},\\\"arguments\\\":[\");\n";
  256. }
  257. if(!empty($o->d)) { foreach($o->d as $k=>$i) {
  258. $c.=" ";
  259. if(preg_match("/^[0-9]+$/",$i)) $c.="a".$k."=(int64_t)(*((int".($Is[$i])."_t*)addr));".(isset($list['signext']['a'.$k])?" a".$k."|=(a".$k.">>".($i*8-1).")&1?-1L<<".($i*8).":0;":"");
  260. $c.="addr+=".$i.";\n"; }
  261. if($hi) $c.=" if(sys_fault) { *str=0; return addr; }\n";}
  262. if($ha && empty($o->p)) {
  263. if(count($is)!=1) $c.=" if(str!=NULL) {\n";
  264. if(!empty($o->d)) {
  265. $d=0; foreach($o->d as $k=>$i) {
  266. $c.=" ".($d?"*str++=',';":"")."*str++='[';";
  267. $c.=" for(ai=0;ai<".$i.";ai++) str".($hs?"":"+")."=s".($hn?"n":"")."printf(str,".($hn?"ends-str,":"")."\"%s0x%x\",ai?\",\":\"\",*((uint8_t*)oaddr++));\n";
  268. $c.=" *str++=']';".($hn?"if(str>=ends) return 0;":"")."\n";
  269. $d=1;
  270. }
  271. }
  272. $c.=" *ps=0; str".($hs?"":"+")."=s".($hn?"n":"")."printf(str,".($hn?"ends-str,":"")."\"],\\\"prefixstr\\\":\\\"%s\\\",\\\"decoded\\\":\\\"\",psb);\n";
  273. $c.=" }\n";
  274. }
  275. if($o->p) { if(!empty($o->i) && $o->i[0]!="") $c.=" if(str!=NULL) ".($ha?"ps":"str").($hs?"":"+")."=s".($hn?"n":"")."printf(".($ha?"ps":"str").($hn?",".($ha?"256":"ends-str"):"").",\"%s \",".$pre."_str(names,op));\n";
  276. $c.=" iaddr=addr".($hi?"-buf_reloc":"")."; goto getopcode;\n"; }
  277. $c.=" }".(!$e?" else":"")."\n";
  278. }
  279. if(!$e) $c.=" names=NULL;\n";
  280. $c.="\n if(str!=NULL) {\n str".($hs?"":"+")."=s".($hn?"n":"")."printf(str,".($hn?"ends-str,":"").$pre."_str(names,op)".(isset($var['c'])&&isset($list['conds'])?",".$pre."_str(conds,c)":"").");\n";
  281. if($hn) $c.=" if(str>=ends) return 0;\n";
  282. if($ha) $c.=" *str++=' ';\n";
  283. else $c.=" if(str-olds<".($il+1).")om=".($il+1)."-(str-olds);else om=1;for(op=0;op<om;op++) *str++=' ';\n";
  284. $c.=" for(op=0;op<sizeof(args) && args[op]!=".$pre."_arg_NONE;op++) {\n";
  285. if($hn) $c.=" if(str>=ends) return 0;\n";
  286. $c.=" if(op".(isset($argdefc["offs"])?"&&args[op-1]!=".$pre."_arg_offs":"").(isset($argdefc["offe"])?"&&args[op]!=".$pre."_arg_offe":"").") { *str++=','; *str++=' '; }\n";
  287. $c.=" switch(args[op]) {\n";
  288. foreach($argdefc as $k=>$v) {
  289. $c.=" case ".$pre."_arg_".$k.": str".($hs?"":"+")."=s".($hn?"n":"")."printf(str,".($hn?"ends-str,":"");
  290. $d=str_replace('^',"(int)iaddr",str_replace('$',"((int)addr".(count($is)==1?"+".reset($is):"").")",str_replace("disasm_",$pre."_",$argdef[$k])));
  291. if(strpos($d,"@")!==false) {
  292. $d=preg_replace("/@([^\[]+)\[([^\]]+)\]/",$pre.'_str($1,$2)',$d);
  293. $c.="\"%s\", ".$d;
  294. } else $c.=$d;
  295. $c.="); "; if($hi&&substr($k,0,5)=="label")$c.="dbg_label=".trim(preg_replace("/^[^,]*,?/","",$d)).";"; $c.="break;\n";
  296. }
  297. $c.=" default: break;\n }\n if(*(str-2)==',')str-=2;\n";
  298. $c.=" }\n";
  299. if($ha)
  300. $c.=" str".($hs?"":"+")."=s".($hn?"n":"")."printf(str,".($hn?"ends-str,":"")."\"\\\"}\");\n";
  301. $c.=" *str=0;\n }\n return ".($hn?"str>=ends?0:":"")."addr".(count($is)==1?"+".reset($is):"").";\n}\n\n";
  302. $c.="#ifdef __cplusplus\n}\n#endif\n\n";
  303. $fn=explode(".",$fn)[0].".h";file_put_contents($fn,$c); echo("DONE: C header ".$fn." saved.\n");