📦
1999 /agent.js
5739 /node_modules/@frida/events/events.js
↻ events
21032 /node_modules/frida-itrace/dist/backend.js
5740 /node_modules/frida-itrace/dist/index.js
↻ frida-itrace
✄
import{TraceBuffer as e,TraceBufferReader as r,TraceSession as t}from"frida-itrace";function s(e){if(null===e)return NULL;const[r,t]=e;switch(r){case"address":{const e=ptr(t);try{e.readVolatile(1)}catch(r){throw new Error(`invalid address: ${e}`)}return e}case"module-export":return Process.getModuleByName(t[0]).getExportByName(t[1]);case"module-offset":return Process.getModuleByName(t[0]).base.add(t[1]);case"symbol":{const e=t,{address:r}=DebugSymbol.fromName(e);return r.isNull()?Module.getGlobalExportByName(e):r}}}const n=new class{session=null;buffer=null;reader=null;drainTimer=null;createBuffer(){return this.buffer=e.create(),this.buffer.location}openBuffer(r){this.buffer=e.open(r)}launchBufferReader(){this.reader=new r(this.buffer),this.drainTimer=setInterval(this.#e,10)}stopBufferReader(){clearInterval(this.drainTimer),this.drainTimer=null,this.#e(),this.reader=null}#e=()=>{const e=this.reader.read();if(0===e.byteLength)return;send({type:"itrace:chunk"},e);const r=this.reader.lost;0!==r&&send({type:"itrace:lost",payload:{lost:r}})};launchTraceSession(e){const r=function(e){const[r,t]=e;switch(r){case"thread":{let e;const r=Process.enumerateThreads();switch(t[0]){case"id":{const s=t[1],n=r.find((e=>e.id===s));if(void 0===n)throw new Error("invalid thread ID");e=n;break}case"index":if(e=r[t[1]],void 0===e)throw new Error("invalid thread index")}return{type:"thread",threadId:e.id}}case"range":return{type:"range",start:s(t[0]),end:s(t[1])}}}(e),n=new t(r,this.buffer);this.session=n,n.events.on("start",((e,r)=>{send({type:"itrace:start",payload:e},r)})),n.events.on("end",(()=>{send({type:"itrace:end"})})),n.events.on("compile",(e=>{send({type:"itrace:compile",payload:e})})),n.events.on("panic",(e=>{console.error(e)})),n.open()}queryProgramName(){return Process.enumerateModules()[0].name}listThreads(){return Process.enumerateThreads()}},a=Object.getOwnPropertyNames(Object.getPrototypeOf(n)).filter((e=>"constructor"!==e));for(const e of a)rpc.exports[e]=n[e].bind(n);
✄
export default e;export{e as EventEmitter,l as once};function e(){e.init.call(this)}e.EventEmitter=e,e.prototype._events=void 0,e.prototype._eventsCount=0,e.prototype._maxListeners=void 0;let t=10;function n(e){if("function"!=typeof e)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof e)}function r(t){return void 0===t._maxListeners?e.defaultMaxListeners:t._maxListeners}function i(e,t,i,o){let s;n(i);let u=e._events;if(void 0===u?(u=e._events=Object.create(null),e._eventsCount=0):(void 0!==u.newListener&&(e.emit("newListener",t,i.listener?i.listener:i),u=e._events),s=u[t]),void 0===s)s=u[t]=i,++e._eventsCount;else{"function"==typeof s?s=u[t]=o?[i,s]:[s,i]:o?s.unshift(i):s.push(i);const n=r(e);if(n>0&&s.length>n&&!s.warned){s.warned=!0;const n=new Error("Possible EventEmitter memory leak detected. "+s.length+" "+String(t)+" listeners added. Use emitter.setMaxListeners() to increase limit");n.name="MaxListenersExceededWarning",n.emitter=e,n.type=t,n.count=s.length,f=n,console.warn(f)}}var f;return e}function o(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function s(e,t,n){const r={fired:!1,wrapFn:void 0,target:e,type:t,listener:n},i=o.bind(r);return i.listener=n,r.wrapFn=i,i}function u(e,t,n){const r=e._events;if(void 0===r)return[];const i=r[t];return void 0===i?[]:"function"==typeof i?n?[i.listener||i]:[i]:n?function(e){const t=new Array(e.length);for(let n=0;n<t.length;++n)t[n]=e[n].listener||e[n];return t}(i):c(i,i.length)}function f(e){const t=this._events;if(void 0!==t){const n=t[e];if("function"==typeof n)return 1;if(void 0!==n)return n.length}return 0}function c(e,t){const n=new Array(t);for(let r=0;r<t;++r)n[r]=e[r];return n}function l(e,t){return new Promise((function(n,r){function i(n){e.removeListener(t,o),r(n)}function o(){"function"==typeof e.removeListener&&e.removeListener("error",i),n([].slice.call(arguments))}h(e,t,o,{once:!0}),"error"!==t&&function(e,t,n){"function"==typeof e.on&&h(e,"error",t,n)}(e,i,{once:!0})}))}function h(e,t,n,r){if("function"==typeof e.on)r.once?e.once(t,n):e.on(t,n);else{if("function"!=typeof e.addEventListener)throw new TypeError('The "emitter" argument must be of type EventEmitter. Received type '+typeof e);e.addEventListener(t,(function i(o){r.once&&e.removeEventListener(t,i),n(o)}))}}Object.defineProperty(e,"defaultMaxListeners",{enumerable:!0,get:function(){return t},set:function(e){if("number"!=typeof e||e<0||Number.isNaN(e))throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received '+e+".");t=e}}),e.init=function(){void 0!==this._events&&this._events!==Object.getPrototypeOf(this)._events||(this._events=Object.create(null),this._eventsCount=0),this._maxListeners=this._maxListeners||void 0},e.prototype.setMaxListeners=function(e){if("number"!=typeof e||e<0||Number.isNaN(e))throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received '+e+".");return this._maxListeners=e,this},e.prototype.getMaxListeners=function(){return r(this)},e.prototype.emit=function(e){const t=[];for(let e=1;e<arguments.length;e++)t.push(arguments[e]);let n="error"===e;const r=this._events;if(void 0!==r)n=n&&void 0===r.error;else if(!n)return!1;if(n){let e;if(t.length>0&&(e=t[0]),e instanceof Error)throw e;const n=new Error("Unhandled error."+(e?" ("+e.message+")":""));throw n.context=e,n}const i=r[e];if(void 0===i)return!1;if("function"==typeof i)Reflect.apply(i,this,t);else{const e=i.length,n=c(i,e);for(let r=0;r<e;++r)Reflect.apply(n[r],this,t)}return!0},e.prototype.addListener=function(e,t){return i(this,e,t,!1)},e.prototype.on=e.prototype.addListener,e.prototype.prependListener=function(e,t){return i(this,e,t,!0)},e.prototype.once=function(e,t){return n(t),this.on(e,s(this,e,t)),this},e.prototype.prependOnceListener=function(e,t){return n(t),this.prependListener(e,s(this,e,t)),this},e.prototype.removeListener=function(e,t){n(t);const r=this._events;if(void 0===r)return this;const i=r[e];if(void 0===i)return this;if(i===t||i.listener===t)0==--this._eventsCount?this._events=Object.create(null):(delete r[e],r.removeListener&&this.emit("removeListener",e,i.listener||t));else if("function"!=typeof i){let n,o=-1;for(let e=i.length-1;e>=0;e--)if(i[e]===t||i[e].listener===t){n=i[e].listener,o=e;break}if(o<0)return this;0===o?i.shift():function(e,t){for(;t+1<e.length;t++)e[t]=e[t+1];e.pop()}(i,o),1===i.length&&(r[e]=i[0]),void 0!==r.removeListener&&this.emit("removeListener",e,n||t)}return this},e.prototype.off=e.prototype.removeListener,e.prototype.removeAllListeners=function(e){const t=this._events;if(void 0===t)return this;if(void 0===t.removeListener)return 0===arguments.length?(this._events=Object.create(null),this._eventsCount=0):void 0!==t[e]&&(0==--this._eventsCount?this._events=Object.create(null):delete t[e]),this;if(0===arguments.length){const e=Object.keys(t);for(let t=0;t<e.length;++t){const n=e[t];"removeListener"!==n&&this.removeAllListeners(n)}return this.removeAllListeners("removeListener"),this._events=Object.create(null),this._eventsCount=0,this}const n=t[e];if("function"==typeof n)this.removeListener(e,n);else if(void 0!==n)for(let t=n.length-1;t>=0;t--)this.removeListener(e,n[t]);return this},e.prototype.listeners=function(e){return u(this,e,!0)},e.prototype.rawListeners=function(e){return u(this,e,!1)},e.listenerCount=function(e,t){return"function"==typeof e.listenerCount?e.listenerCount(t):f.call(e,t)},e.prototype.listenerCount=f,e.prototype.eventNames=function(){return this._eventsCount>0?Reflect.ownKeys(this._events):[]};
✄
export const code='#line 2 "backend.ts"\n#include <string.h>\n#include <gum/gummodulemap.h>\n#include <gum/gumstalker.h>\n#include <json-glib/json-glib.h>\n\n#define RED_ZONE_SIZE 128\n\n#define SCRATCH_REG_BOTTOM ARM64_REG_X21\n#define SCRATCH_REG_TOP ARM64_REG_X28\n\n#define SCRATCH_REG_INDEX(r) ((r) - SCRATCH_REG_BOTTOM)\n#define SCRATCH_REG_OFFSET(r) (SCRATCH_REG_INDEX (r) * 8)\n\ntypedef enum _ITraceState ITraceState;\ntypedef struct _ITraceSession ITraceSession;\ntypedef struct _ITraceBuffer ITraceBuffer;\n\nenum _ITraceState\n{\n  ITRACE_STATE_CREATED,\n  ITRACE_STATE_STARTING,\n  ITRACE_STATE_STARTED,\n  ITRACE_STATE_ENDED,\n};\n\nstruct _ITraceSession\n{\n  ITraceState state;\n  ITraceBuffer * buffer;\n  guint64 pending_size;\n  guint64 saved_regs[2];\n  guint64 stack[64];\n  guint64 scratch_regs[SCRATCH_REG_TOP - SCRATCH_REG_BOTTOM + 1];\n  guint64 log_buf[1969];\n  GumAddress write_impl;\n  GumModuleMap * modules;\n};\n\nextern ITraceSession session;\nextern void * end_address;\n\nextern void on_start (const gchar * meta_json, const GumCpuContext * cpu_context, guint length);\nextern void on_end (void);\nextern void on_compile (const gchar * meta_json);\nextern void on_panic (const gchar * message);\n\nstatic void on_first_block_hit (GumCpuContext * cpu_context, gpointer user_data);\nstatic void on_end_instruction_hit (GumCpuContext * cpu_context, gpointer user_data);\nstatic void add_cpu_register_meta (JsonBuilder * meta, const gchar * name, guint size);\nstatic void add_block_write_meta (JsonBuilder * meta, guint block_offset, guint cpu_reg_index);\nstatic void add_memory_address (JsonBuilder * builder, GumAddress address);\nstatic gchar * make_json (JsonBuilder ** builder);\nstatic arm64_reg pick_scratch_register (cs_regs regs_read, uint8_t num_regs_read, cs_regs regs_written, uint8_t num_regs_written);\nstatic arm64_reg register_to_full_size_register (arm64_reg reg);\nstatic void emit_scratch_register_restore (GumArm64Writer * cw, arm64_reg reg);\nstatic void emit_buffer_write_impl (GumArm64Writer * cw);\n\nstatic void panic (const char * format, ...);\n\nvoid\ninit (void)\n{\n  session.modules = gum_module_map_new ();\n}\n\nvoid\nfinalize (void)\n{\n  g_object_unref (session.modules);\n}\n\nvoid\ntransform (GumStalkerIterator * iterator,\n           GumStalkerOutput * output,\n           gpointer user_data)\n{\n  GumArm64Writer * cw = output->writer.arm64;\n  csh capstone = gum_stalker_iterator_get_capstone (iterator);\n\n  guint num_instructions = 0;\n  GumAddress block_address = 0;\n  guint log_buf_offset = 16;\n  arm64_reg prev_session_reg = ARM64_REG_INVALID;\n\n  JsonBuilder * meta = json_builder_new_immutable ();\n  json_builder_begin_object (meta);\n\n  cs_insn * insn;\n  while (gum_stalker_iterator_next (iterator, &insn))\n  {\n    num_instructions++;\n\n    gboolean is_first_in_block = num_instructions == 1;\n    gboolean is_last_in_block = cs_insn_group (capstone, insn, CS_GRP_JUMP) || cs_insn_group (capstone, insn, CS_GRP_RET);\n\n    if (is_first_in_block)\n    {\n      block_address = insn->address;\n\n      json_builder_set_member_name (meta, "writes");\n      json_builder_begin_array (meta);\n    }\n\n    if (session.state == ITRACE_STATE_CREATED)\n    {\n      session.state = ITRACE_STATE_STARTING;\n      gum_stalker_iterator_put_callout (iterator, on_first_block_hit, NULL, NULL);\n    }\n\n    if (end_address != NULL && GUM_ADDRESS (end_address) == insn->address)\n    {\n      gum_stalker_iterator_put_callout (iterator, on_end_instruction_hit, NULL, NULL);\n    }\n\n    cs_regs regs_read, regs_written;\n    uint8_t num_regs_read, num_regs_written;\n    cs_regs_access (capstone, insn, regs_read, &num_regs_read, regs_written, &num_regs_written);\n    for (uint8_t i = 0; i != num_regs_read; i++)\n      regs_read[i] = register_to_full_size_register (regs_read[i]);\n    for (uint8_t i = 0; i != num_regs_written; i++)\n      regs_written[i] = register_to_full_size_register (regs_written[i]);\n\n    arm64_reg session_reg = is_last_in_block\n        ? SCRATCH_REG_TOP\n        : pick_scratch_register (regs_read, num_regs_read, regs_written, num_regs_written);\n\n    if (session_reg != prev_session_reg)\n    {\n      if (prev_session_reg != ARM64_REG_INVALID)\n        gum_arm64_writer_put_mov_reg_reg (cw, session_reg, prev_session_reg);\n      else\n        gum_arm64_writer_put_ldr_reg_address (cw, session_reg, GUM_ADDRESS (&session));\n    }\n\n    if (prev_session_reg != ARM64_REG_INVALID && session_reg != prev_session_reg)\n      emit_scratch_register_restore (cw, prev_session_reg);\n\n    if (is_first_in_block)\n    {\n      gum_arm64_writer_put_str_reg_reg_offset (cw, ARM64_REG_LR, session_reg, G_STRUCT_OFFSET (ITraceSession, log_buf) + 8);\n      add_block_write_meta (meta, insn->address - block_address, 33);\n    }\n\n    if (is_last_in_block)\n    {\n      gum_arm64_writer_put_stp_reg_reg_reg_offset (cw, ARM64_REG_X27, ARM64_REG_LR,\n          session_reg, G_STRUCT_OFFSET (ITraceSession, saved_regs), GUM_INDEX_SIGNED_OFFSET);\n      gum_arm64_writer_put_ldr_reg_address (cw, ARM64_REG_X27, block_address);\n      gum_arm64_writer_put_str_reg_reg_offset (cw, ARM64_REG_X27, session_reg, G_STRUCT_OFFSET (ITraceSession, log_buf));\n      gum_arm64_writer_put_ldr_reg_u64 (cw, ARM64_REG_X27, log_buf_offset);\n      gum_arm64_writer_put_str_reg_reg_offset (cw, ARM64_REG_X27, session_reg, G_STRUCT_OFFSET (ITraceSession, pending_size));\n\n      if (session.write_impl == 0 ||\n          !gum_arm64_writer_can_branch_directly_between (cw, cw->pc, session.write_impl))\n      {\n        gconstpointer after_write_impl = cw->code + 1;\n\n        gum_arm64_writer_put_b_label (cw, after_write_impl);\n\n        session.write_impl = cw->pc;\n        emit_buffer_write_impl (cw);\n\n        gum_arm64_writer_put_label (cw, after_write_impl);\n      }\n\n      gum_arm64_writer_put_bl_imm (cw, session.write_impl);\n\n      gum_arm64_writer_put_ldp_reg_reg_reg_offset (cw, ARM64_REG_X27, ARM64_REG_LR,\n          session_reg, G_STRUCT_OFFSET (ITraceSession, saved_regs), GUM_INDEX_SIGNED_OFFSET);\n\n      emit_scratch_register_restore (cw, session_reg);\n    }\n\n    gum_stalker_iterator_keep (iterator);\n\n    if (is_last_in_block)\n      continue;\n\n    guint block_offset = (insn->address + insn->size) - block_address;\n\n    for (uint8_t i = 0; i != num_regs_written; i++)\n    {\n      arm64_reg reg = regs_written[i];\n      gboolean is_scratch_reg = reg >= SCRATCH_REG_BOTTOM && reg <= SCRATCH_REG_TOP;\n      if (is_scratch_reg)\n      {\n        gum_arm64_writer_put_str_reg_reg_offset (cw, reg,\n            session_reg, G_STRUCT_OFFSET (ITraceSession, scratch_regs) + SCRATCH_REG_OFFSET (reg));\n      }\n    }\n\n    for (uint8_t i = 0; i != num_regs_written; i++)\n    {\n      arm64_reg reg = regs_written[i];\n\n      guint cpu_reg_index;\n      arm64_reg source_reg;\n      gsize size;\n      arm64_reg temp_reg = ARM64_REG_INVALID;\n\n      if (reg == ARM64_REG_SP)\n      {\n        temp_reg = ARM64_REG_X0;\n\n        cpu_reg_index = 1;\n        source_reg = temp_reg;\n        size = 8;\n      }\n      else if (reg >= ARM64_REG_X0 && reg <= ARM64_REG_X28)\n      {\n        cpu_reg_index = 3 + (reg - ARM64_REG_X0);\n        source_reg = reg;\n        size = 8;\n      }\n      else if (reg == ARM64_REG_FP)\n      {\n        cpu_reg_index = 32;\n        source_reg = reg;\n        size = 8;\n      }\n      else if (reg == ARM64_REG_LR)\n      {\n        cpu_reg_index = 33;\n        source_reg = reg;\n        size = 8;\n      }\n      else if (reg >= ARM64_REG_Q0 && reg <= ARM64_REG_Q31)\n      {\n        cpu_reg_index = 34 + (reg - ARM64_REG_Q0);\n        source_reg = reg;\n        size = 16;\n      }\n      else if (reg == ARM64_REG_NZCV)\n      {\n        temp_reg = ARM64_REG_X0;\n\n        cpu_reg_index = 2;\n        source_reg = temp_reg;\n        size = 8;\n      }\n      else if (reg == ARM64_REG_XZR || reg == ARM64_REG_WZR)\n      {\n        continue;\n      }\n      else\n      {\n        panic ("Unhandled register: %s", cs_reg_name (capstone, reg));\n        while (TRUE)\n          ;\n      }\n\n      if (temp_reg != ARM64_REG_INVALID)\n        gum_arm64_writer_put_str_reg_reg_offset (cw, temp_reg, session_reg, G_STRUCT_OFFSET (ITraceSession, saved_regs));\n\n      if (reg == ARM64_REG_SP)\n        gum_arm64_writer_put_mov_reg_reg (cw, temp_reg, ARM64_REG_SP);\n      else if (reg == ARM64_REG_NZCV)\n        gum_arm64_writer_put_mov_reg_nzcv (cw, temp_reg);\n\n      gsize offset = G_STRUCT_OFFSET (ITraceSession, log_buf) + log_buf_offset;\n      gsize alignment_delta = offset % size;\n      if (alignment_delta != 0)\n        offset += size - alignment_delta;\n      // TODO: Handle large offsets\n      gum_arm64_writer_put_str_reg_reg_offset (cw, source_reg, session_reg, offset);\n      add_block_write_meta (meta, block_offset, cpu_reg_index);\n      log_buf_offset += size;\n\n      if (temp_reg != ARM64_REG_INVALID)\n        gum_arm64_writer_put_ldr_reg_reg_offset (cw, temp_reg, session_reg, G_STRUCT_OFFSET (ITraceSession, saved_regs));\n    }\n\n    prev_session_reg = session_reg;\n  }\n\n  json_builder_end_array (meta);\n\n  json_builder_set_member_name (meta, "address");\n  add_memory_address (meta, block_address);\n\n  json_builder_set_member_name (meta, "size");\n  json_builder_add_int_value (meta, (insn->address + insn->size) - block_address);\n\n  json_builder_set_member_name (meta, "compiled");\n  json_builder_begin_object (meta);\n  {\n    guint compiled_code_size = gum_arm64_writer_offset (cw);\n\n    json_builder_set_member_name (meta, "address");\n    add_memory_address (meta, cw->pc - compiled_code_size);\n\n    json_builder_set_member_name (meta, "size");\n    json_builder_add_int_value (meta, compiled_code_size);\n  }\n  json_builder_end_object (meta);\n\n  GumModule * m = gum_module_map_find (session.modules, block_address);\n  if (m != NULL)\n  {\n    const GumMemoryRange * range = gum_module_get_range (m);\n\n    json_builder_set_member_name (meta, "name");\n    gchar * name = g_strdup_printf ("%s!0x%x", gum_module_get_name (m), (guint) (block_address - range->base_address));\n    json_builder_add_string_value (meta, name);\n    g_free (name);\n\n    json_builder_set_member_name (meta, "module");\n    json_builder_begin_object (meta);\n\n    json_builder_set_member_name (meta, "path");\n    json_builder_add_string_value (meta, gum_module_get_path (m));\n\n    json_builder_set_member_name (meta, "base");\n    add_memory_address (meta, range->base_address);\n\n    json_builder_end_object (meta);\n  }\n  else\n  {\n    json_builder_set_member_name (meta, "name");\n    add_memory_address (meta, block_address);\n  }\n\n  json_builder_end_object (meta);\n\n  gchar * json = make_json (&meta);\n  on_compile (json);\n  g_free (json);\n}\n\nstatic void\non_first_block_hit (GumCpuContext * cpu_context,\n                    gpointer user_data)\n{\n  if (session.state != ITRACE_STATE_STARTING)\n    return;\n  session.state = ITRACE_STATE_STARTED;\n\n  memcpy (session.scratch_regs, cpu_context->x + (SCRATCH_REG_BOTTOM - ARM64_REG_X0), sizeof (session.scratch_regs));\n\n  JsonBuilder * meta = json_builder_new_immutable ();\n  json_builder_begin_array (meta);\n  add_cpu_register_meta (meta, "pc", sizeof (cpu_context->pc));\n  add_cpu_register_meta (meta, "sp", sizeof (cpu_context->sp));\n  add_cpu_register_meta (meta, "nzcv", sizeof (cpu_context->nzcv));\n  for (guint i = 0; i != G_N_ELEMENTS (cpu_context->x); i++)\n  {\n    gchar * name = g_strdup_printf ("x%u", i);\n    add_cpu_register_meta (meta, name, sizeof (cpu_context->x[0]));\n    g_free (name);\n  }\n  add_cpu_register_meta (meta, "fp", sizeof (cpu_context->fp));\n  add_cpu_register_meta (meta, "lr", sizeof (cpu_context->lr));\n  for (guint i = 0; i != G_N_ELEMENTS (cpu_context->v); i++)\n  {\n    gchar * name = g_strdup_printf ("v%u", i);\n    add_cpu_register_meta (meta, name, sizeof (cpu_context->v[0]));\n    g_free (name);\n  }\n  json_builder_end_array (meta);\n\n  gchar * json = make_json (&meta);\n  on_start (json, cpu_context, sizeof (GumCpuContext));\n  g_free (json);\n}\n\nstatic void\non_end_instruction_hit (GumCpuContext * cpu_context,\n                        gpointer user_data)\n{\n  if (session.state != ITRACE_STATE_STARTED)\n    return;\n  session.state = ITRACE_STATE_ENDED;\n\n  on_end ();\n}\n\nstatic void\nadd_cpu_register_meta (JsonBuilder * meta,\n                       const gchar * name,\n                       guint size)\n{\n  json_builder_begin_object (meta);\n\n  json_builder_set_member_name (meta, "name");\n  json_builder_add_string_value (meta, name);\n\n  json_builder_set_member_name (meta, "size");\n  json_builder_add_int_value (meta, size);\n\n  json_builder_end_object (meta);\n}\n\nstatic void\nadd_block_write_meta (JsonBuilder * meta,\n                      guint block_offset,\n                      guint cpu_ctx_offset)\n{\n  json_builder_begin_array (meta);\n  json_builder_add_int_value (meta, block_offset);\n  json_builder_add_int_value (meta, cpu_ctx_offset);\n  json_builder_end_array (meta);\n}\n\nstatic void\nadd_memory_address (JsonBuilder * builder,\n                    GumAddress address)\n{\n  gchar * str = g_strdup_printf ("0x%" G_GINT64_MODIFIER "x", address);\n  json_builder_add_string_value (builder, str);\n  g_free (str);\n}\n\nstatic gchar *\nmake_json (JsonBuilder ** builder)\n{\n  JsonBuilder * b = *builder;\n  *builder = NULL;\n\n  JsonNode * node = json_builder_get_root (b);\n  gchar * json = json_to_string (node, FALSE);\n  json_node_unref (node);\n\n  g_object_unref (b);\n\n  return json;\n}\n\nstatic arm64_reg\npick_scratch_register (cs_regs regs_read,\n                       uint8_t num_regs_read,\n                       cs_regs regs_written,\n                       uint8_t num_regs_written)\n{\n  arm64_reg candidate;\n\n  for (candidate = SCRATCH_REG_TOP; candidate != SCRATCH_REG_BOTTOM - 1; candidate--)\n  {\n    gboolean available = TRUE;\n\n    for (uint8_t i = 0; i != num_regs_read; i++)\n    {\n      if (regs_read[i] == candidate)\n      {\n        available = FALSE;\n        break;\n      }\n    }\n    if (!available)\n      continue;\n\n    for (uint8_t i = 0; i != num_regs_written; i++)\n    {\n      if (regs_written[i] == candidate)\n      {\n        available = FALSE;\n        break;\n      }\n    }\n    if (!available)\n      continue;\n\n    break;\n  }\n\n  return candidate;\n}\n\nstatic arm64_reg\nregister_to_full_size_register (arm64_reg reg)\n{\n  switch (reg)\n  {\n    case ARM64_REG_SP:\n    case ARM64_REG_FP:\n    case ARM64_REG_LR:\n    case ARM64_REG_NZCV:\n    case ARM64_REG_XZR:\n    case ARM64_REG_WZR:\n      return reg;\n  }\n\n  if (reg >= ARM64_REG_X0 && reg <= ARM64_REG_X28)\n    return reg;\n  if (reg >= ARM64_REG_W0 && reg <= ARM64_REG_W28)\n    return ARM64_REG_X0 + (reg - ARM64_REG_W0);\n  if (reg == ARM64_REG_W29)\n    return ARM64_REG_FP;\n  if (reg == ARM64_REG_W30)\n    return ARM64_REG_LR;\n\n  if (reg >= ARM64_REG_Q0 && reg <= ARM64_REG_Q31)\n    return reg;\n  if (reg >= ARM64_REG_V0 && reg <= ARM64_REG_V31)\n    return ARM64_REG_Q0 + (reg - ARM64_REG_V0);\n  if (reg >= ARM64_REG_D0 && reg <= ARM64_REG_D31)\n    return ARM64_REG_Q0 + (reg - ARM64_REG_D0);\n  if (reg >= ARM64_REG_S0 && reg <= ARM64_REG_S31)\n    return ARM64_REG_Q0 + (reg - ARM64_REG_S0);\n  if (reg >= ARM64_REG_H0 && reg <= ARM64_REG_H31)\n    return ARM64_REG_Q0 + (reg - ARM64_REG_H0);\n  if (reg >= ARM64_REG_B0 && reg <= ARM64_REG_B31)\n    return ARM64_REG_Q0 + (reg - ARM64_REG_B0);\n\n  return reg;\n}\n\nstatic void\nemit_scratch_register_restore (GumArm64Writer * cw,\n                               arm64_reg reg)\n{\n  gum_arm64_writer_put_ldr_reg_reg_offset (cw, reg,\n      reg, G_STRUCT_OFFSET (ITraceSession, scratch_regs) + SCRATCH_REG_OFFSET (reg));\n}\n\nstatic void\nemit_buffer_write_impl (GumArm64Writer * cw)\n{\n  static const guint32 write_impl[] = {\n    0x9108a39bU, /* add x27, x28, 0x228         */\n\n    0xa9b75f78U, /* stp x24, x23, [x27, -0x90]! */\n    0xa9015776U, /* stp x22, x21, [x27, 0x10]   */\n    0xa9024f74U, /* stp x20, x19, [x27, 0x20]   */\n    0xa9032f6cU, /* stp x12, x11, [x27, 0x30]   */\n    0xa904276aU, /* stp x10, x9, [x27, 0x40]    */\n    0xa9050b68U, /* stp x8, x2, [x27, 0x50]     */\n    0xa9060361U, /* stp x1, x0, [x27, 0x60]     */\n    0xa9077b7dU, /* stp x29, x30, [x27, 0x70]   */\n    0x9101c37dU, /* add x29, x27, 0x70          */\n\n    0xd53b4200U, /* mrs x0, nzcv                */\n    0xf9004360U, /* str x0, [x27, 0x80]         */\n\n    0xf9400793U, /* ldr x19, [x28, 8]           */\n\n    0xf9400b94U, /* ldr x20, [x28, 0x10]        */\n    0x9109a395U, /* add x21, x28, 0x268         */\n\n    0xf9400668U, /* ldr x8, [x19, 8]            */\n    0xf9400e69U, /* ldr x9, [x19, 0x18]         */\n    0xc8dffe6aU, /* ldar x10, [x19]             */\n    0xeb08015fU, /* cmp x10, x8                 */\n    0x54000081U, /* b.ne not_empty              */\n    0xf9400e6aU, /* ldr x10, [x19, 0x18]        */\n    0xd100054aU, /* sub x10, x10, 1             */\n    0x14000008U, /* b check_headroom            */\n    /* not_empty:                               */\n    0x540000a2U, /* b.hs tail_has_wrapped       */\n    0xf9400e6bU, /* ldr x11, [x19, 0x18]        */\n    0xaa2803ecU, /* mvn x12, x8                 */\n    0x8b0c014aU, /* add x10, x10, x12           */\n    0x14000002U, /* b compute_final_headroom    */\n    /* tail_has_wrapped:                        */\n    0xaa2803ebU, /* mvn x11, x8                 */\n    /* compute_final_headroom:                  */\n    0x8b0b014aU, /* add x10, x10, x11           */\n    /* check_headroom:                          */\n    0xeb14015fU, /* cmp x10, x20                */\n    0x540000e2U, /* b.hs sufficient_headroom    */\n    0x91004268U, /* add x8, x19, 0x10           */\n    /* retry:                                   */\n    0xc85ffd09U, /* ldaxr x9, [x8]              */\n    0x91000529U, /* add x9, x9, 1               */\n    0xc80afd09U, /* stlxr w10, x9, [x8]         */\n    0x35ffffaaU, /* cbnz w10, retry             */\n    0x14000018U, /* b beach                     */\n    /* sufficient_headroom:                     */\n    0x8b14010aU, /* add x10, x8, x20            */\n    0x9ac9094bU, /* udiv x11, x10, x9           */\n    0x9b09a978U, /* msub x24, x11, x9, x10      */\n    0xeb08031fU, /* cmp x24, x8                 */\n    0x540000c9U, /* b.ls copy_with_wrap         */\n    0x8b080268U, /* add x8, x19, x8             */\n    0x91008100U, /* add x0, x8, 0x20            */\n    0xaa1503e1U, /* mov x1, x21                 */\n    0xaa1403e2U, /* mov x2, x20                 */\n    0x1400000bU, /* b do_memcpy                 */\n    /* copy_with_wrap:                          */\n    0xf9400e69U, /* ldr x9, [x19, 0x18]         */\n    0xcb080136U, /* sub x22, x9, x8             */\n    0x91008277U, /* add x23, x19, 0x20          */\n    0x8b0802e0U, /* add x0, x23, x8             */\n    0xaa1503e1U, /* mov x1, x21                 */\n    0xaa1603e2U, /* mov x2, x22                 */\n    0x94000012U, /* bl itrace_memcpy            */\n    0x8b1602a1U, /* add x1, x21, x22            */\n    0xcb160282U, /* sub x2, x20, x22            */\n    0xaa1703e0U, /* mov x0, x23                 */\n    /* do_memcpy:                               */\n    0x9400000eU, /* bl itrace_memcpy            */\n    0x91002268U, /* add x8, x19, 8              */\n    0xc89ffd18U, /* stlr x24, [x8]              */\n    /* beach:                                   */\n    0xf9404360U, /* ldr x0, [x27, 0x80]         */\n    0xd51b4200U, /* msr nzcv, x0                */\n\n    0xa9477b7dU, /* ldp x29, x30, [x27, 0x70]   */\n    0xa9460361U, /* ldp x1, x0, [x27, 0x60]     */\n    0xa9450b68U, /* ldp x8, x2, [x27, 0x50]     */\n    0xa944276aU, /* ldp x10, x9, [x27, 0x40]    */\n    0xa9432f6cU, /* ldp x12, x11, [x27, 0x30]   */\n    0xa9424f74U, /* ldp x20, x19, [x27, 0x20]   */\n    0xa9415776U, /* ldp x22, x21, [x27, 0x10]   */\n    0xa8c95f78U, /* ldp x24, x23, [x27], 0x90   */\n\n    0xd65f03c0U, /* ret                         */\n\n    /* itrace_memcpy:                           */\n    0xd343fc48U, /* lsr x8, x2, 3               */\n    0xb40000a8U, /* cbz x8, beach2              */\n    0xf8408429U, /* ldr x9, [x1], 8             */\n    0xf8008409U, /* str x9, [x0], 8             */\n    0xd1000508U, /* sub x8, x8, 1               */\n    0xb5ffffa8U, /* cbnz x8, again              */\n    /* beach2:                                  */\n    0xd65f03c0U, /* ret                         */\n  };\n\n  gum_arm64_writer_put_bytes (cw, (const guint8 *) write_impl, sizeof (write_impl));\n}\n\nstatic void\npanic (const char * format,\n       ...)\n{\n  va_list args;\n  va_start (args, format);\n  gchar * message = g_strdup_vprintf (format, args);\n  va_end (args);\n\n  on_panic (message);\n\n  g_free (message);\n}\n';
✄
var e,t,r,n,i,o,a,s,c,d,l,f,p=this&&this.__classPrivateFieldGet||function(e,t,r,n){if("a"===r&&!n)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!n:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===r?n:"a"===r?n.call(e):n?n.value:t.get(e)},h=this&&this.__classPrivateFieldSet||function(e,t,r,n,i){if("m"===n)throw new TypeError("Private method is not writable");if("a"===n&&!i)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!i:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===n?i.call(e,r):i?i.value=r:t.set(e,r),r};import*as u from"./backend.js";import m from"events";const w=Process.pointerSize,v=2*w,_=3*w,y=function(){const e=[248,95,188,169,246,87,1,169,244,79,2,169,253,123,3,169,253,195,0,145,24,0,64,249,8,32,0,145,8,253,223,200,8,1,24,235,97,0,0,84,20,0,128,210,32,0,0,20,245,3,1,170,243,3,0,170,9,1,0,84,31,1,2,235,20,49,130,154,104,2,24,139,1,129,0,145,224,3,21,170,226,3,20,170,15,0,0,20,105,14,64,249,8,1,9,139,31,1,2,235,20,49,130,154,54,1,24,203,119,130,0,145,225,2,24,139,224,3,21,170,226,3,22,170,126,2,0,88,192,3,63,214,160,2,22,139,130,2,22,203,225,3,23,170,222,1,0,88,192,3,63,214,136,2,24,139,105,14,64,249,10,9,201,154,72,161,9,155,104,254,159,200,224,3,20,170,253,123,67,169,244,79,66,169,246,87,65,169,248,95,196,168,192,3,95,214,0,0,0,0,18,52,86,120,154,188,222,255],t=Memory.alloc(Process.pageSize);Memory.patchCode(t,e.length,(t=>{t.writeByteArray(e),t.add(e.length-w).writePointer(Module.getExportByName(null,"memcpy"))}));const r=new NativeFunction(t,"uint",["pointer","pointer","uint"],{exceptions:"propagate"});return Object.defineProperty(r,"$code",{value:t}),r}(),g=function(e){let t,r=!1;return function(...n){return r||(t=e(...n),r=!0),t}}((function(){const e=NativeFunction;return t=[["mach_task_self",()=>{const e=Module.getExportByName(null,"mach_task_self_").readU32();return()=>e}],["mach_port_deallocate",e,"int",["uint","uint"]],["task_for_pid",e,"int",["uint","int","pointer"]],["mach_vm_remap",e,"int",["uint","pointer","size_t","size_t","int","uint","uint64","uint","pointer","pointer","uint"]],["mach_vm_deallocate",e,"int",["uint","uint64","uint64"]]],t.reduce(((e,t)=>(function(e,t){const[r]=t;Object.defineProperty(e,r,{configurable:!0,get(){let n=null;if(2===t.length){const[,e]=t;n=e()}else{const[,e,i,o]=t,a=Module.findExportByName(null,r);null!==a&&(n=new e(a,i,o,M))}return Object.defineProperty(e,r,{value:n}),n}})}(e,t),e)),{});var t}));export class TraceSession{constructor(n,c){e.add(this),this.strategy=n,this.buffer=c,this.events=new m,t.set(this,void 0),r.set(this,void 0),i.set(this,((e,t,r)=>{const n=JSON.parse(e.readUtf8String()),i=t.readByteArray(r);this.events.emit("start",n,i)})),o.set(this,(()=>{setImmediate((()=>{Stalker.unfollow(p(this,r,"f")),this.events.emit("end")}))})),a.set(this,(e=>{const t=JSON.parse(e.readUtf8String());t.address=ptr(t.address);const r=t.compiled;r.address=ptr(r.address);const n=t.module;void 0!==n&&(n.base=ptr(n.base)),this.events.emit("compile",t)})),s.set(this,(e=>{const t=e.readUtf8String();this.events.emit("panic",t)}));const d=Memory.alloc(16384);d.add(w).writePointer(c.regionBase);const l=Memory.alloc(w);"range"===n.type&&l.writePointer(n.end),h(this,t,new CModule(u.code,{session:d,end_address:l,on_start:new NativeCallback(p(this,i,"f"),"void",["pointer","pointer","uint"]),on_end:new NativeCallback(p(this,o,"f"),"void",[]),on_compile:new NativeCallback(p(this,a,"f"),"void",["pointer"]),on_panic:new NativeCallback(p(this,s,"f"),"void",["pointer"])}),"f")}open(){const{strategy:t}=this;if("thread"===t.type)p(this,e,"m",n).call(this,t.threadId);else{const i=this;Interceptor.attach(t.start,(function(){void 0===p(i,r,"f")&&p(i,e,"m",n).call(i,this.threadId)}))}}}t=new WeakMap,r=new WeakMap,i=new WeakMap,o=new WeakMap,a=new WeakMap,s=new WeakMap,e=new WeakSet,n=function(e){h(this,r,e,"f"),Stalker.follow(e,{transform:p(this,t,"f").transform})};export class TraceBuffer{get location(){const e=Process.id,{regionBase:t,regionSize:r}=this;return JSON.stringify({pid:e,regionBase:t,regionSize:r})}constructor(e,t){this.regionBase=e,this.regionSize=t}static create(e={}){const t=4*w,r=e.capacity??33554432,n=function(e){const{pageSize:t}=Process,r=e%t;return 0===r?e:e+(t-r)}(t+r),i=Memory.alloc(n);return i.add(_).writePointer(ptr(r)),new TraceBuffer(i,n)}static open(e){if("darwin"!==Process.platform)throw new Error("shared memory is only supported on Darwin for now");const{pid:t,regionBase:r,regionSize:n}=JSON.parse(e),i=g(),o=i.mach_task_self(),a=Memory.alloc(4);S("task_for_pid",i.task_for_pid(o,t,a));const s=a.readU32();try{const e=Memory.alloc(16),t=e.add(8),a=t.add(4);S("mach_vm_remap",i.mach_vm_remap(o,e,n,0,1,s,uint64(r),0,t,a,2));const c=ptr(e.readU64().toString()),d=new TraceBuffer(c,n);return Script.bindWeak(d,k.bind(null,c,n)),d}finally{i.mach_port_deallocate(o,s)}}}export class TraceBufferReader{get lost(){return p(this,f,"f").readPointer().toUInt32()}constructor(e,t={}){this.buffer=e,c.set(this,void 0),d.set(this,void 0),l.set(this,new ArrayBuffer(0)),f.set(this,void 0);const r=t.chunkSize??4194304;h(this,c,Memory.alloc(r),"f"),h(this,d,r,"f"),h(this,f,e.regionBase.add(v),"f")}read(){const e=y(this.buffer.regionBase,p(this,c,"f"),p(this,d,"f"));return 0===e?p(this,l,"f"):p(this,c,"f").readByteArray(e)}}function k(e,t){const r=g();r.mach_vm_deallocate(r.mach_task_self(),uint64(e.toString()),t)}function S(e,t){if(0!==t)throw new Error(`${e}() failed (kr=${t})`)}c=new WeakMap,d=new WeakMap,l=new WeakMap,f=new WeakMap;const M={exceptions:"propagate"};