From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from nx208.node02.secure-mailgate.com (nx208.node02.secure-mailgate.com [192.162.87.208]) by sourceware.org (Postfix) with ESMTPS id 050D038930ED for ; Fri, 26 Feb 2021 02:46:28 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 050D038930ED Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=trande.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=zied.guermazi@trande.de Received: from host202.checkdomain.de ([185.137.168.148]) by node02.secure-mailgate.com with esmtps (TLSv1.2:AES128-GCM-SHA256:128) (Exim 4.92) (envelope-from ) id 1lFT98-00BfBD-DP for gdb-patches@sourceware.org; Fri, 26 Feb 2021 03:46:27 +0100 X-SecureMailgate-Identity: zied.guermazi@trande.de;host202.checkdomain.de Received: from Trande0001.fritz.box (x4dbd6140.dyn.telefonica.de [77.189.97.64]) (Authenticated sender: zied.guermazi@trande.de) by host202.checkdomain.de (Postfix) with ESMTPSA id DA5D03880D1; Fri, 26 Feb 2021 03:46:25 +0100 (CET) From: Zied Guermazi To: gdb-patches@sourceware.org Cc: Zied Guermazi Subject: [PATCH 3/8] start/stop btrace with coresight etm and parse etm buffer. nat independant Date: Fri, 26 Feb 2021 03:45:57 +0100 Message-Id: <20210226024602.55057-4-zied.guermazi@trande.de> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210226024602.55057-1-zied.guermazi@trande.de> References: <20210226024602.55057-1-zied.guermazi@trande.de> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-PPP-Message-ID: <20210226024626.3433054.49911@host202.checkdomain.de> X-PPP-Vhost: trande.de X-Originating-IP: 185.137.168.148 X-SecureMailgate-Domain: host202.checkdomain.de X-SecureMailgate-Username: 185.137.168.148 Authentication-Results: secure-mailgate.com; auth=pass smtp.auth=185.137.168.148@host202.checkdomain.de X-SecureMailgate-Outgoing-Class: ham X-SecureMailgate-Outgoing-Evidence: SB/global_tokens (7.25261762358e-06) X-Recommended-Action: accept X-Filter-ID: Pt3MvcO5N4iKaDQ5O6lkdGlMVN6RH8bjRMzItlySaT8uIDw72Vf4PQRcK+T5qXT7PUtbdvnXkggZ 3YnVId/Y5jcf0yeVQAvfjHznO7+bT5wgSQOko5ya3orWH1MkzQXa2oPZqVS5i0KNMNtVCi0tRw/C h5SE4jAyhe1COeASyU/1g1aArDTYuIE+yrJuwBJI4ld5rdi2ZxohSIq+dqifZoVY3IcDeckxfee+ NDQ6wUl3g/WbBekzB3IK8RY7uNAEcY1i02TJefD768F5oV2iM8C0xB8SW32wy2mbLZXD/P/xjgGi IdaTDXlxoyUe5P+Jut5PpkrBQueV+Yg5wqLK/LXDLRhLABXs81Y8X58rOcwLMK9HC+pUQBAyR03+ Yzd8ARsynxDH0D+SLDJWdESXziw50BoEYB44qFPH6be8XgtMhiMRK0C70oXENkWqJaNtpfX1h/uL cDQJCG2naSen4S0KEAnwyE9dte+FkDKSV99EDBffVZVjmVaNbG4ZJG7F2RgQw3d3zmVen9wp80qQ nk5/t+UnI24Hleg6UWHjmGlvyMjbyNpr4xR6RL2C9+qlIny++hg9dJLqN5zmWqF/oNe6FVV7drXD mtOldfpWzeXX3Vs0+OVZ6o01Ur0UfsSgVqahaS1Xn3nbmTfiR5jKRrn6qQ/in5NA6oG3bP7L0DnU JleWftUulkbC12DciiOUAQy3WRoWhjJ4ABRp4spTBKsH/WzE78WB+6LKJkk4wWAos7Vk+4I720v2 H9/mQncon4T7OymHvLHT1C7MG/JfBypdI5fiiW9IKehsy+TwqApFXdcOXXm38/++NKnQrU/tOnYQ psOL3D4WKYPb9hiQqsMR3pimW+H6hrLs7bihM+ep7Sq+vnK5vq335GkOmYDoHPDsFqo1t5bEBI0m 4NsB3v57rn7svr0CR7c5hAqOktxJ52+eJVfFyi5Fe59LNAUyE59PyHj0n7C3jNCL5MndKzwJWw42 swm4bO6gacpMpzI93NKmpOx249IDJgHZhSqYgJJFthw94zyDVRbqPxaxhXoarW2MF3gazIzgmJi5 UydShOH22SRgbHWq1uciMDoDhcd9NG1JDoOknqc6qrb4AiZPF6HXPq5gLm4Q4ElmvUALMK9HC+pU QBAyR03+Yzd87yCUgX8YuF5WBQr1Bq861zvA3BXN5HBbApl4eIrLaWewxjLyThsLecb51qdaSQev MS+4ayUpOtEhdxekWDmK9g== X-Report-Abuse-To: spam@node04.secure-mailgate.com X-Spam-Status: No, score=-10.4 required=5.0 tests=BAYES_00, GIT_PATCH_0, JMQ_SPF_NEUTRAL, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 26 Feb 2021 02:46:31 -0000 This patch extend branch tracing by adding the functions nedded to start and stop tracing, as well decoding them. This patch is not providing an implementation of the mechanisms on the target. gdb/ChangeLog * btrace.c (ftrace_remove_last_insn): New. (cs_etm_get_etmv3_config): New. (cs_etm_get_etmv4_config): New. (cs_etm_update_btrace_with_inst_range): New. (cs_etm_update_btrace_with_exception): New. (cs_etm_update_btrace_with_trace_on): New. (cs_etm_trace_element_callback): New. (cs_etm_create_decoder): New. (cs_etm_free_decoder): New. (btrace_etm_readmem_callback): New. (cs_etm_add_mem_access_callback): New. (cs_etm_process_data_block): New. (btrace_print_all): New. (btrace_compute_ftrace_etm): New. (btrace_compute_ftrace_1): add handling of CoreSight traces. (btrace_enable): add error message if ETM unavailable. (btrace_stitch_trace): add handling of CoreSight traces. (maint_info_btrace_cmd): add handling of CoreSight trace format. * btrace.h (record_btrace_reg_entry): new. (btrace_insn): add a vector of record_btrace_reg_entry. * record-btrace.c (record_btrace_target::fetch_registers): fetch registers from insn->registers when available gdbsupport/ChangeLog * btrace-common.h (cs_etmv3_trace_params): New (cs_etmv4_trace_params): New. (cs_etm_trace_params): New. (cs_etm_decoder_params): New (btrace_data_etm_config): New. (btrace_data_etm): New. (btrace_data): add a btrace_data_etm. * btrace-common.cc (btrace_data::fini): handle CoreSight traces. (btrace_data::empty): handle CoreSight traces. (btrace_data_append): handle CoreSight traces. --- gdb/ChangeLog | 28 +- gdb/btrace.c | 591 +++++++++++++++++++++++++++++++++++- gdb/btrace.h | 20 ++ gdb/record-btrace.c | 21 +- gdbsupport/ChangeLog | 27 +- gdbsupport/btrace-common.cc | 42 ++- gdbsupport/btrace-common.h | 106 ++++++- 7 files changed, 816 insertions(+), 19 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 46e7a2f2416..1b998ef2624 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,29 @@ +2021-02-25 Zied Guermazi + + * btrace.c (ftrace_remove_last_insn): New. + * btrace.c (cs_etm_get_etmv3_config): New. + * btrace.c (cs_etm_get_etmv4_config): New. + * btrace.c (cs_etm_update_btrace_with_inst_range): New. + * btrace.c (cs_etm_update_btrace_with_exception): New. + * btrace.c (cs_etm_update_btrace_with_trace_on): New. + * btrace.c (cs_etm_trace_element_callback): New. + * btrace.c (cs_etm_create_decoder): New. + * btrace.c (cs_etm_free_decoder): New. + * btrace.c (btrace_etm_readmem_callback): New. + * btrace.c (cs_etm_add_mem_access_callback): New. + * btrace.c (cs_etm_process_data_block): New. + * btrace.c (btrace_print_all): New. + * btrace.c (btrace_compute_ftrace_etm): New. + * btrace.c (btrace_compute_ftrace_1): add handling of CoreSight traces. + * btrace.c (btrace_enable): add error message if ETM unavailable. + * btrace.c (btrace_stitch_trace): add handling of CoreSight traces. + * btrace.c (maint_info_btrace_cmd): add handling of CoreSight trace + format. + * btrace.h (record_btrace_reg_entry): new. + * btrace.h (btrace_insn): add a vector of record_btrace_reg_entry. + * record-btrace.c (record_btrace_target::fetch_registers): fetch + registers from insn->registers when available + 2021-02-25 Zied Guermazi * record-btrace.c (record_btrace_print_etm_conf): New. @@ -9,7 +35,7 @@ * record-btrace.c (_initialize_record_btrace): add commands for ETM traces. * record.c (record_start): add starting ETM traces. -2021-02-02 Zied Guermazi +2021-02-25 Zied Guermazi * Makefile.in LIBOPENCSD_C_API: set the flag. * config.in LIBOPENCSD_C_API: undefine it if diff --git a/gdb/btrace.c b/gdb/btrace.c index c697f37f46c..dcb89964b81 100644 --- a/gdb/btrace.c +++ b/gdb/btrace.c @@ -227,6 +227,23 @@ ftrace_function_switched (const struct btrace_function *bfun, return 0; } +#if defined (HAVE_LIBOPENCSD_C_API) + +/* set a record_btrace_reg_entry. */ + +static void +btrace_reg_set (struct record_btrace_reg_entry *reg, + const struct regcache *regcache, int regnum, const gdb_byte *value) +{ + struct gdbarch *gdbarch = regcache->arch (); + + reg->num = regnum; + reg->len = register_size (gdbarch, regnum); + memcpy(reg->buffer, value, reg->len); +} + +#endif //defined (HAVE_LIBOPENCSD_C_API) + /* Allocate and initialize a new branch trace function segment at the end of the trace. BTINFO is the branch trace information for the current thread. @@ -257,6 +274,7 @@ ftrace_new_function (struct btrace_thread_info *btinfo, } btinfo->functions.emplace_back (mfun, fun, number, insn_offset, level); + ftrace_debug (&btinfo->functions.back (), "new function"); return &btinfo->functions.back (); } @@ -671,6 +689,32 @@ ftrace_update_insns (struct btrace_function *bfun, const btrace_insn &insn) ftrace_debug (bfun, "update insn"); } +#if defined (HAVE_LIBOPENCSD_C_API) + /* remove last instruction from BFUN's list. + This function is not generic and is granted to work properly + only if the same removed instruction will be added later. */ + +static void +ftrace_remove_last_insn (struct btrace_thread_info *btinfo) +{ + struct btrace_function *bfun; + + /* If we didn't have a function, we return. */ + if (btinfo->functions.empty ()) + return; + /* If we had a gap before, we return. */ + bfun = &btinfo->functions.back (); + if (bfun->errcode != 0) + return; + if (!bfun->insn.empty ()) + bfun->insn.pop_back (); + else + { + /* a valid function must have at least one insn */ + error (_("Attempt to remove last instruction from an empty function")); + } +} +#endif /* #if defined (HAVE_LIBOPENCSD_C_API)*/ /* Classify the instruction at PC. */ static enum btrace_insn_class @@ -1193,7 +1237,7 @@ pt_btrace_insn_flags (const struct pt_insn &insn) static btrace_insn pt_btrace_insn (const struct pt_insn &insn) { - return {(CORE_ADDR) insn.ip, (gdb_byte) insn.size, + return {(CORE_ADDR) insn.ip, (gdb_byte) insn.size,{}, pt_reclassify_insn (insn.iclass), pt_btrace_insn_flags (insn)}; } @@ -1502,6 +1546,533 @@ btrace_compute_ftrace_pt (struct thread_info *tp, #endif /* defined (HAVE_LIBIPT) */ +#if defined (HAVE_LIBOPENCSD_C_API) + +struct cs_etm_decoder +{ + /* The tree representing CoreSight architecture in the SoC. */ + dcd_tree_handle_t dcd_tree; + + /* Callback function to allow the decoder to access program memory. */ + Fn_MemAcc_CB mem_access; + + /* thread_info of traced thread. */ + struct thread_info *t_info; + + /* returned value of previously processed block. */ + ocsd_datapath_resp_t prev_return; + + /* ARM architecture version of associated core. */ + ocsd_arch_version_t arch_version; + + /* list of gaps in the execution record. */ + std::vector &gaps; +}; + +/* fills a ocsd_etmv3_cfg from a cs_etm_trace_params */ + +static void +cs_etm_get_etmv3_config (const struct cs_etm_trace_params *params, + ocsd_etmv3_cfg *config) +{ + config->reg_idr = params->etmv3.reg_idr; + config->reg_ctrl = params->etmv3.reg_ctrl; + config->reg_ccer = params->etmv3.reg_ccer; + config->reg_trc_id = params->etmv3.reg_trc_id; + config->arch_ver = (ocsd_arch_version_t)params->arch_ver; + config->core_prof = (ocsd_core_profile_t)params->core_profile; +} + +/* fills a ocsd_etmv4_cfg from a cs_etm_trace_params */ + +static void +cs_etm_get_etmv4_config (const struct cs_etm_trace_params *params, + ocsd_etmv4_cfg *config) +{ + config->reg_configr = params->etmv4.reg_configr; + config->reg_traceidr = params->etmv4.reg_traceidr; + config->reg_idr0 = params->etmv4.reg_idr0; + config->reg_idr1 = params->etmv4.reg_idr1; + config->reg_idr2 = params->etmv4.reg_idr2; + config->reg_idr8 = params->etmv4.reg_idr8; + config->reg_idr9 = 0; + config->reg_idr10 = 0; + config->reg_idr11 = 0; + config->reg_idr12 = 0; + config->reg_idr13 = 0; + config->arch_ver = (ocsd_arch_version_t)params->arch_ver; + config->core_prof = (ocsd_core_profile_t)params->core_profile; +} + +#define ARM_PS_REGNUM 25 /* Contains processor status */ + +/* update btrace in the case of an instruction range */ + +static void +cs_etm_update_btrace_with_inst_range (const void *context, + const ocsd_generic_trace_elem *elem) +{ + struct cs_etm_decoder *etm_decoder; + struct thread_info *tp; + struct btrace_thread_info *btinfo; + struct btrace_function *bfun; + struct btrace_insn insn; + CORE_ADDR pc; + int size; + struct gdbarch *gdbarch; + unsigned int cpsr; + struct record_btrace_reg_entry reg; + + if (elem->elem_type == OCSD_GEN_TRC_ELEM_INSTR_RANGE) + { + etm_decoder = (struct cs_etm_decoder *)context; + if (!etm_decoder->t_info ) + return; + tp = etm_decoder->t_info; + btinfo = &tp->btrace; + gdbarch = target_gdbarch (); + + pc = elem->st_addr; + for (int i = 0; i< elem->num_instr_range; i++) + { + insn.pc = pc; + try + { + size = gdb_insn_length (gdbarch, pc); + } + catch (const gdb_exception_error &err) + { + error (_("Failed to get the size of the instruction.")); + } + bfun = ftrace_update_function (btinfo, pc ); + insn.iclass=BTRACE_INSN_OTHER; + insn.size = size; + if (etm_decoder->arch_version == ARCH_V7) + { + switch(elem->isa) + { + case ocsd_isa_arm: + cpsr = 0; + break; + case ocsd_isa_thumb2: + cpsr = 0x20; + break; + case ocsd_isa_tee: + cpsr = 0x1000020; + break; + case ocsd_isa_jazelle: + cpsr = 0x1000000; + break; + default: + cpsr = 0; + } + btrace_reg_set (®, get_thread_regcache(tp), + ARM_PS_REGNUM, (gdb_byte *)&cpsr); + insn.registers.push_back (reg); + } + if (i == elem->num_instr_range -1) + { + switch (elem->last_i_type) + { + case OCSD_INSTR_BR: + case OCSD_INSTR_BR_INDIRECT: + switch (elem->last_i_subtype ) + { + case OCSD_S_INSTR_V8_RET: + case OCSD_S_INSTR_V8_ERET: + case OCSD_S_INSTR_V7_IMPLIED_RET: + insn.iclass=BTRACE_INSN_RETURN; + break; + case OCSD_S_INSTR_BR_LINK: + insn.iclass=BTRACE_INSN_CALL; + break; + case OCSD_S_INSTR_NONE: + insn.iclass=BTRACE_INSN_JUMP; + } + break; + case OCSD_INSTR_ISB: + case OCSD_INSTR_DSB_DMB: + case OCSD_INSTR_WFI_WFE: + case OCSD_INSTR_OTHER: + insn.iclass=BTRACE_INSN_OTHER; + break; + default: + break; + } + } + ftrace_update_insns (bfun, insn); + pc = pc + size; + } + } +} +#undef ARM_PS_REGNUM + +#define ARM_EXCEPTION_UNDEFINED_INSTRUCTION 9 + +/* update btrace in the case of an exception */ + +static void +cs_etm_update_btrace_with_exception (const void *context, + const ocsd_generic_trace_elem *elem) +{ + struct cs_etm_decoder *etm_decoder; + struct thread_info *tp; + struct btrace_thread_info *btinfo; + + etm_decoder = (struct cs_etm_decoder *)context; + if (!etm_decoder->t_info ) + return; + tp = etm_decoder->t_info; + btinfo = &tp->btrace; + /* handle the implementation of breakpoints in gdb for arm (v7) architecture + using undefined instructions */ + + if (etm_decoder->arch_version == ARCH_V7) + { + if (elem->elem_type==OCSD_GEN_TRC_ELEM_EXCEPTION) + { + if (elem->exception_number == ARM_EXCEPTION_UNDEFINED_INSTRUCTION) + { + DEBUG ("handle breakpoints implementation in gdb for armv7"); + ftrace_remove_last_insn(btinfo); + } + } + } +} +#undef ARM_EXCEPTION_UNDEFINED_INSTRUCTION + +/* update btrace in the case of a trace on */ + +static void +cs_etm_update_btrace_with_trace_on (const void *context, + const ocsd_generic_trace_elem *elem) +{ + struct cs_etm_decoder *etm_decoder; + struct thread_info *tp; + struct btrace_thread_info *btinfo; + + etm_decoder = (struct cs_etm_decoder *)context; + if (!etm_decoder->t_info ) + return; + tp = etm_decoder->t_info; + btinfo = &tp->btrace; + + if (elem->elem_type==OCSD_GEN_TRC_ELEM_TRACE_ON) + { + if (elem->trace_on_reason != TRACE_ON_NORMAL) + ftrace_new_gap (btinfo, elem->trace_on_reason, etm_decoder->gaps); + } +} + +/* callback function when a ocsd_generic_trace_elem is emitted */ + +static ocsd_datapath_resp_t +cs_etm_trace_element_callback (const void *context, + const ocsd_trc_index_t indx, + const uint8_t trace_chan_id, + const ocsd_generic_trace_elem *elem) +{ + char str_buffer[128]; + if(ocsd_gen_elem_str(elem, str_buffer,128) == OCSD_OK) + DEBUG("ETM trace_element: index= %d, channel= 0x%x, %s", + indx, trace_chan_id, str_buffer); + ocsd_datapath_resp_t resp = OCSD_RESP_CONT; + switch (elem->elem_type) { + case OCSD_GEN_TRC_ELEM_TRACE_ON: + cs_etm_update_btrace_with_trace_on(context, elem); + break; + case OCSD_GEN_TRC_ELEM_INSTR_RANGE: + cs_etm_update_btrace_with_inst_range(context, elem); + break; + case OCSD_GEN_TRC_ELEM_EXCEPTION: + cs_etm_update_btrace_with_exception(context, elem); + break; + case OCSD_GEN_TRC_ELEM_UNKNOWN: + case OCSD_GEN_TRC_ELEM_EO_TRACE: + case OCSD_GEN_TRC_ELEM_NO_SYNC: + case OCSD_GEN_TRC_ELEM_EXCEPTION_RET: + case OCSD_GEN_TRC_ELEM_TIMESTAMP: + case OCSD_GEN_TRC_ELEM_PE_CONTEXT: + case OCSD_GEN_TRC_ELEM_ADDR_NACC: + case OCSD_GEN_TRC_ELEM_CYCLE_COUNT: + case OCSD_GEN_TRC_ELEM_ADDR_UNKNOWN: + case OCSD_GEN_TRC_ELEM_EVENT: + case OCSD_GEN_TRC_ELEM_SWTRACE: + case OCSD_GEN_TRC_ELEM_CUSTOM: + default: + break; + } + return resp; +} + +/* create a cs_etm_decoder and initialize it */ + +static bool +cs_etm_create_decoder (struct cs_etm_trace_params *t_params, + struct cs_etm_decoder *decoder) +{ + const char *decoder_name; + ocsd_etmv3_cfg config_etmv3; + ocsd_etmv4_cfg trace_config_etmv4; + void *trace_config; + uint8_t csid; + + switch (t_params->protocol) { + case CS_ETM_PROTO_ETMV3: + case CS_ETM_PROTO_PTM: + cs_etm_get_etmv3_config(t_params, &config_etmv3); + decoder_name = (t_params->protocol == CS_ETM_PROTO_ETMV3) ? + OCSD_BUILTIN_DCD_ETMV3 : + OCSD_BUILTIN_DCD_PTM; + trace_config = &config_etmv3; + decoder->arch_version = ARCH_V7; + break; + case CS_ETM_PROTO_ETMV4i: + cs_etm_get_etmv4_config(t_params, &trace_config_etmv4); + decoder_name = OCSD_BUILTIN_DCD_ETMV4I; + trace_config = &trace_config_etmv4; + decoder->arch_version = ARCH_V8; + break; + default: + decoder->arch_version = ARCH_UNKNOWN; + return false; + } + + if (ocsd_dt_create_decoder(decoder->dcd_tree, + decoder_name, + OCSD_CREATE_FLG_FULL_DECODER, + trace_config, &csid)) + return false; + if (ocsd_dt_set_gen_elem_outfn(decoder->dcd_tree, + cs_etm_trace_element_callback, + decoder)) + return false; + decoder->prev_return = OCSD_RESP_CONT; + return true; +} + +/* allocate a cs_etm_decoder and initialize it */ + +static struct cs_etm_decoder * +cs_etm_alloc_decoder (struct thread_info *tp, int num_cpu, + struct cs_etm_decoder_params d_params, + std::vector * t_params) +{ + + dcd_tree_handle_t dcdtree_handle; + ocsd_dcd_tree_src_t src_type =OCSD_TRC_SRC_SINGLE; + uint32_t deformatterCfgFlags =0; + struct cs_etm_decoder *decoder; + int i; + bool ret; + + if (d_params.formatted) + src_type = OCSD_TRC_SRC_FRAME_FORMATTED; + if (d_params.frame_aligned) + deformatterCfgFlags |= OCSD_DFRMTR_FRAME_MEM_ALIGN; + if (d_params.fsyncs) + deformatterCfgFlags |= OCSD_DFRMTR_HAS_FSYNCS; + if (d_params.hsyncs) + deformatterCfgFlags |= OCSD_DFRMTR_HAS_HSYNCS; + if (d_params.reset_on_4x_sync) + deformatterCfgFlags |= OCSD_DFRMTR_RESET_ON_4X_FSYNC; + + dcdtree_handle = ocsd_create_dcd_tree(src_type, + deformatterCfgFlags); + + if (dcdtree_handle == C_API_INVALID_TREE_HANDLE) + return NULL; + decoder=(struct cs_etm_decoder*)xmalloc (sizeof(struct cs_etm_decoder)); + decoder->dcd_tree = dcdtree_handle; + + for (i = 0; i < num_cpu; i++) { + ret = cs_etm_create_decoder(&(t_params->at(i)), + decoder); + if (ret == false) + { + ocsd_destroy_dcd_tree(decoder->dcd_tree); + free(decoder); + return NULL; + } + + } + decoder->t_info =tp; + return decoder; +} + +/* free a cs_etm_decoder */ + +static void +cs_etm_free_decoder (struct cs_etm_decoder *decoder) +{ + if (!decoder) + return; + + ocsd_destroy_dcd_tree(decoder->dcd_tree); + decoder->dcd_tree = NULL; + decoder->t_info = NULL; + free(decoder); +} + +/* A callback function to allow the trace decoder to read the inferior's + memory. */ + +static uint32_t +btrace_etm_readmem_callback (const void *p_context, const ocsd_vaddr_t address, + const ocsd_mem_space_acc_t mem_space, + const uint32_t reqBytes, uint8_t *byteBuffer) +{ + int result, errcode; + + result = (int) reqBytes; + try + { + errcode = target_read_code ((CORE_ADDR) address, byteBuffer, reqBytes); + if (errcode != 0) + result = 0; + } + catch (const gdb_exception_error &error) + { + result = 0; + } + + return result; +} + +/* add memory access callback to the decoder */ + +static ocsd_err_t +cs_etm_add_mem_access_callback (struct cs_etm_decoder *decoder, + CORE_ADDR start, CORE_ADDR end, + Fn_MemAcc_CB p_cb_func) +{ + ocsd_err_t error; + error = ocsd_dt_add_callback_mem_acc(decoder->dcd_tree, + (ocsd_vaddr_t) start, (ocsd_vaddr_t) end, + OCSD_MEM_SPACE_ANY, p_cb_func, decoder); + if (error != OCSD_OK) + decoder->mem_access = p_cb_func; + return (error); + +} + +/* process an etm traces data block */ + +static int +cs_etm_process_data_block (struct cs_etm_decoder *decoder, + uint64_t index, const uint8_t *buf, + size_t len, size_t *consumed) +{ + int ret = 0; + ocsd_datapath_resp_t cur = OCSD_RESP_CONT; + ocsd_datapath_resp_t prev_return = decoder->prev_return; + size_t processed = 0; + uint32_t count; + + while (processed < len) { + if (OCSD_DATA_RESP_IS_WAIT(prev_return)) { + cur = ocsd_dt_process_data(decoder->dcd_tree, + OCSD_OP_FLUSH, + 0, + 0, + NULL, + NULL); + } else if (OCSD_DATA_RESP_IS_CONT(prev_return)) { + cur = ocsd_dt_process_data(decoder->dcd_tree, + OCSD_OP_DATA, + index + processed, + len - processed, + &buf[processed], + &count); + processed += count; + } else { + DEBUG_FTRACE ("ocsd_dt_process_data returned with %d.\n", cur); + ret = -EINVAL; + break; + } + + /* Return to the input code if the packet buffer is full. + Flushing will get done once the packet buffer has been + processed. */ + if (OCSD_DATA_RESP_IS_WAIT(cur)) + break; + + prev_return = cur; + } + + decoder->prev_return = cur; + *consumed = processed; + + return ret; +} + +/* print all function in a btrace */ + +static void btrace_print_all (struct btrace_thread_info *btinfo) +{ + std::vector functions; + + functions = btinfo->functions; + for (const btrace_function &function : functions) + ftrace_debug (&function, ""); +} + +static void +btrace_compute_ftrace_etm (struct thread_info *tp, + const struct btrace_data_etm *btrace, + std::vector &gaps) +{ + struct btrace_thread_info *btinfo; + struct cs_etm_decoder *decoder; + int errcode; + ocsd_err_t ocsd_error; + size_t consumed; + + + DEBUG_FTRACE ("btrace->size is 0x%x for thread %s", + (unsigned int)(btrace->size), print_thread_id (tp)); + if (btrace->size == 0) + return; + + btinfo = &tp->btrace; + if (btinfo->functions.empty ()) + btinfo->level = 0; + + decoder = cs_etm_alloc_decoder(tp,btrace->config.num_cpu, + btrace->config.etm_decoder_params, + btrace->config.etm_trace_params); + if (decoder == NULL) + error (_("Failed to allocate ARM CoreSight ETM Trace decoder.")); + + ocsd_error = cs_etm_add_mem_access_callback(decoder, + (CORE_ADDR)0x0L, (CORE_ADDR) -1L, + btrace_etm_readmem_callback); + if (ocsd_error!= OCSD_OK) + error (_("Failed to add CoreSight Trace decoder memory access callback.")); + + errcode = cs_etm_process_data_block(decoder, + 0, btrace->data, + btrace->size, &consumed); + if (errcode!=0) + error (_("Failed to decode ARM CoreSight ETM Trace.")); + ftrace_compute_global_level_offset (btinfo); + btrace_add_pc (tp); + btrace_print_all(btinfo); + cs_etm_free_decoder(decoder); + +} +#else /* defined (HAVE_LIBOPENCSD_C_API) */ + +static void +btrace_compute_ftrace_etm (struct thread_info *tp, + const struct btrace_data_etm *btrace, + std::vector &gaps) +{ + + internal_error (__FILE__, __LINE__, _("Unexpected branch trace format.")); +} +#endif /* defined (HAVE_LIBOPENCSD_C_API) */ + /* Compute the function branch trace from a block branch trace BTRACE for a thread given by BTINFO. If CPU is not NULL, overwrite the cpu in the branch trace configuration. This is currently only used for the PT @@ -1531,6 +2102,10 @@ btrace_compute_ftrace_1 (struct thread_info *tp, btrace_compute_ftrace_pt (tp, &btrace->variant.pt, gaps); return; + + case BTRACE_FORMAT_ETM: + btrace_compute_ftrace_etm (tp, &btrace->variant.etm, gaps); + return; } internal_error (__FILE__, __LINE__, _("Unknown branch trace format.")); @@ -1599,6 +2174,10 @@ btrace_enable (struct thread_info *tp, const struct btrace_config *conf) if (conf->format == BTRACE_FORMAT_PT) error (_("Intel Processor Trace support was disabled at compile time.")); #endif /* !defined (HAVE_LIBIPT) */ +#if !defined (HAVE_LIBOPENCSD_C_API) + if (conf->format == BTRACE_FORMAT_ETM) + error (_("ARM CoreSight Trace support was disabled at compile time.")); +#endif /* !defined (HAVE_LIBOPENCSD_C_API) */ DEBUG ("enable thread %s (%s)", print_thread_id (tp), target_pid_to_str (tp->ptid).c_str ()); @@ -1791,6 +2370,9 @@ btrace_stitch_trace (struct btrace_data *btrace, struct thread_info *tp) case BTRACE_FORMAT_PT: /* Delta reads are not supported. */ return -1; + case BTRACE_FORMAT_ETM: + /* Delta reads are not supported. */ + return -1; } internal_error (__FILE__, __LINE__, _("Unknown branch trace format.")); @@ -3413,6 +3995,11 @@ maint_info_btrace_cmd (const char *args, int from_tty) } break; #endif /* defined (HAVE_LIBIPT) */ +#if defined (HAVE_LIBOPENCSD_C_API) + case BTRACE_FORMAT_ETM: + printf_unfiltered (_("Version: %s.\n"), ocsd_get_version_str()); + break; +#endif /* defined (HAVE_LIBOPENCSD_C_API) */ } } @@ -3487,7 +4074,7 @@ first."), maint_btrace_clear_packet_history_cmd, _("Clears the branch tracing packet history.\n\ Discards the raw branch tracing data but not the execution history data."), - &maint_btrace_cmdlist); +&maint_btrace_cmdlist); add_cmd ("clear", class_maintenance, maint_btrace_clear_cmd, _("Clears the branch tracing data.\n\ diff --git a/gdb/btrace.h b/gdb/btrace.h index 8f6ce32103d..5d734896632 100644 --- a/gdb/btrace.h +++ b/gdb/btrace.h @@ -34,6 +34,12 @@ # include #endif +#if defined (HAVE_LIBOPENCSD_C_API) +# include +# include +# include +#endif + #include struct thread_info; @@ -63,6 +69,17 @@ enum btrace_insn_flag }; DEF_ENUM_FLAGS_TYPE (enum btrace_insn_flag, btrace_insn_flags); +/* extend MAX_BTRACE_REGISTER_SIZE if targets with registers +bigger than 64 bits are considered */ +#define MAX_BTRACE_REGISTER_SIZE 8 +/* a register entry in btrace_insn*/ +struct record_btrace_reg_entry +{ + unsigned short num; + unsigned short len; + gdb_byte buffer[MAX_BTRACE_REGISTER_SIZE * sizeof (gdb_byte)]; +}; + /* A branch trace instruction. This represents a single instruction in a branch trace. */ @@ -74,6 +91,9 @@ struct btrace_insn /* The size of this instruction in bytes. */ gdb_byte size; + /* a vector of registers */ + std::vector registers; + /* The instruction class of this instruction. */ enum btrace_insn_class iclass; diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c index 39ac9aafc28..107abd7e653 100644 --- a/gdb/record-btrace.c +++ b/gdb/record-btrace.c @@ -1576,18 +1576,27 @@ record_btrace_target::fetch_registers (struct regcache *regcache, int regno) struct gdbarch *gdbarch; int pcreg; + insn = btrace_insn_get (replay); + gdb_assert (insn != NULL); + if (!insn->registers.empty()) + { + for(int i = 0; i < insn->registers.size(); i++) + { + if (insn->registers.operator[](i).num==regno) + { + regcache->raw_supply (regno, insn->registers.operator[](i).buffer); + return; + } + } + } gdbarch = regcache->arch (); pcreg = gdbarch_pc_regnum (gdbarch); if (pcreg < 0) return; - - /* We can only provide the PC register. */ + /* We can only provide the PC register here. */ if (regno >= 0 && regno != pcreg) return; - insn = btrace_insn_get (replay); - gdb_assert (insn != NULL); - regcache->raw_supply (regno, &insn->pc); } else @@ -3020,7 +3029,6 @@ cmd_record_btrace_start (const char *args, int from_tty) } } - /* The "show record btrace replay-memory-access" command. */ static void @@ -3250,7 +3258,6 @@ This format may not be available on all processors."), _("Show record options."), &show_record_btrace_cmdlist, "show record btrace ", 0, &show_record_cmdlist); - add_cmd ("auto", class_support, cmd_set_record_btrace_cpu_auto, _("\ Automatically determine the cpu to be used for trace decode."), &set_record_btrace_cpu_cmdlist); diff --git a/gdbsupport/ChangeLog b/gdbsupport/ChangeLog index e14bdf109b3..587bc08e58c 100644 --- a/gdbsupport/ChangeLog +++ b/gdbsupport/ChangeLog @@ -1,19 +1,32 @@ +2021-02-25 Zied Guermazi + + * btrace-common.h (cs_etmv3_trace_params): New + * btrace-common.h (cs_etmv4_trace_params): New. + * btrace-common.h (cs_etm_trace_params): New. + * btrace-common.h (cs_etm_decoder_params): New + * btrace-common.h (btrace_data_etm_config): New. + * btrace-common.h (btrace_data_etm): New. + * btrace-common.h (btrace_data): add a btrace_data_etm. + * btrace-common.cc (btrace_data::fini): handle CoreSight traces. + * btrace-common.cc (btrace_data::empty): handle CoreSight traces. + * btrace-common.cc (btrace_data_append): handle CoreSight traces. + 2021-02-25 Zied Guermazi * gdbsupport/btrace-common.h (btrace_format): add BTRACE_FORMAT_ETM to the enum. - * gdbsupport/btrace-common.h (btrace_cpu_vendor): add CV_ARM to the enum. - * gdbsupport/btrace-common.h (btrace_config_etm): new struct. - * gdbsupport/btrace-common.h (btrace_config): add btrace_config_etm etm. - * gdbsupport/btrace-common.cc (btrace_format_string): add BTRACE_FORMAT_ETM. - * gdbsupport/btrace-common.cc (btrace_format_short_string): add + * btrace-common.h (btrace_cpu_vendor): add CV_ARM to the enum. + * btrace-common.h (btrace_config_etm): new struct. + * btrace-common.h (btrace_config): add btrace_config_etm etm. + * btrace-common.cc (btrace_format_string): add BTRACE_FORMAT_ETM. + * btrace-common.cc (btrace_format_short_string): add BTRACE_FORMAT_ETM. 2021-02-25 Zied Guermazi - * gdbsupport/common.m4: check --with-arm-cs configuration + * common.m4: check --with-arm-cs configuration flag, perf_event and opencsd_c_api to set compilation flags. - * gdbsupport/configure: Regenerated + * configure: Regenerated 2021-02-05 Paul E. Murphy diff --git a/gdbsupport/btrace-common.cc b/gdbsupport/btrace-common.cc index 461f769ed51..8e31c8a65dd 100644 --- a/gdbsupport/btrace-common.cc +++ b/gdbsupport/btrace-common.cc @@ -62,7 +62,6 @@ btrace_format_short_string (enum btrace_format format) case BTRACE_FORMAT_ETM: return "etm"; - } internal_error (__FILE__, __LINE__, _("Unknown branch trace format")); @@ -87,6 +86,12 @@ btrace_data::fini () case BTRACE_FORMAT_PT: xfree (variant.pt.data); return; + + case BTRACE_FORMAT_ETM: + /* Variant.etm.data can be null if no new traces are collected. */ + if (variant.etm.data!=NULL) + xfree (variant.etm.data); + return; } internal_error (__FILE__, __LINE__, _("Unkown branch trace format.")); @@ -107,6 +112,9 @@ btrace_data::empty () const case BTRACE_FORMAT_PT: return (variant.pt.size == 0); + + case BTRACE_FORMAT_ETM: + return (variant.etm.size == 0); } internal_error (__FILE__, __LINE__, _("Unkown branch trace format.")); @@ -192,6 +200,38 @@ btrace_data_append (struct btrace_data *dst, } } return 0; + + case BTRACE_FORMAT_ETM: + switch (dst->format) + { + default: + return -1; + + case BTRACE_FORMAT_NONE: + dst->format = BTRACE_FORMAT_ETM; + dst->variant.etm.data = NULL; + dst->variant.etm.size = 0; + + /* fall-through. */ + case BTRACE_FORMAT_ETM: + { + gdb_byte *data; + size_t size; + + size = src->variant.etm.size + dst->variant.etm.size; + data = (gdb_byte *) xmalloc (size); + + memcpy (data, dst->variant.etm.data, dst->variant.etm.size); + memcpy (data + dst->variant.etm.size, src->variant.etm.data, + src->variant.etm.size); + + xfree (dst->variant.etm.data); + + dst->variant.etm.data = data; + dst->variant.etm.size = size; + } + } + return 0; } internal_error (__FILE__, __LINE__, _("Unkown branch trace format.")); diff --git a/gdbsupport/btrace-common.h b/gdbsupport/btrace-common.h index 7f3cabfde77..5bc6f8dbd0f 100644 --- a/gdbsupport/btrace-common.h +++ b/gdbsupport/btrace-common.h @@ -157,7 +157,6 @@ struct btrace_config /* The ARM CoreSight ETM Trace configuration. */ struct btrace_config_etm etm; - }; /* Branch trace in BTS format. */ @@ -189,6 +188,108 @@ struct btrace_data_pt size_t size; }; +/* Parameters needed for decoding ETMv3 traces. + See open source coresight trace decoder library (opencsd) + for further details. */ +struct cs_etmv3_trace_params { + uint32_t reg_ctrl; + uint32_t reg_trc_id; + uint32_t reg_ccer; + uint32_t reg_idr; +}; + +/* Parameters needed for decoding ETMv4 traces. + See open source coresight trace decoder library (opencsd) + for further details. */ +struct cs_etmv4_trace_params { + uint32_t reg_idr0; + uint32_t reg_idr1; + uint32_t reg_idr2; + uint32_t reg_idr8; + uint32_t reg_configr; + uint32_t reg_traceidr; +}; + +/* The following enums are indexed starting with 1 to align with the + open source coresight trace decoder library (opencsd). */ +enum { + CS_ETM_PROTO_ETMV3 = 1, + CS_ETM_PROTO_ETMV4i, + CS_ETM_PROTO_ETMV4d, + CS_ETM_PROTO_PTM, +}; + +/* The following enum must be aligned with the + open source coresight trace decoder library (opencsd). */ + +/* Core Architecture Version */ +enum { + ARCHITECTURE_UNKNOWN, /* unknown architecture */ + ARCHITECTURE_CUSTOM, /* None ARM, custom architecture */ + ARCHITECTURE_V7, /* V7 architecture */ + ARCHITECTURE_V8, /* V8 architecture */ + ARCHITECTURE_V8r3, /* V8.3 architecture */ +}; + +/* The following enum must be aligned with the + open source coresight trace decoder library (opencsd). */ + +/* Core Profile */ +enum { + PROFILE_UNKNOWN, /* Unknown profile */ + PROFILE_CORTEX_M, /* Cortex-M profile */ + PROFILE_CORTEX_R, /* Cortex-R profile */ + PROFILE_CORTEX_A, /* Cortex-A profile */ + PROFILE_CUSTOM, /* None ARM, custom arch profile */ +}; + +/* parameters of trace source */ +struct cs_etm_trace_params { + struct btrace_cpu cpu; + int arch_ver; + int core_profile; + int protocol; + union { + struct cs_etmv3_trace_params etmv3; + struct cs_etmv4_trace_params etmv4; + }; +}; + +/* parameters of trace sink/decoder */ +struct cs_etm_decoder_params { + uint8_t formatted :1, + fsyncs :1, + hsyncs :1, + frame_aligned :1, + reset_on_4x_sync :1, + __res :3; +}; + +/* Configuration information to go with the etm trace data. */ +struct btrace_data_etm_config +{ + /* The number of cpu (trace sources). */ + int num_cpu; + std::vector *etm_trace_params; + struct cs_etm_decoder_params etm_decoder_params; +}; + +/* Branch trace in arm Processor Trace format. */ +struct btrace_data_etm +{ + /* Some configuration information to go with the data. */ + struct btrace_data_etm_config config; + + /* The trace data. */ + gdb_byte *data; + + /* The size of DATA in bytes. */ + size_t size; + + /* trace id for this thread. set to 0xFF to ignore it during parsing */ + int trace_id; +}; + /* The branch trace data. */ struct btrace_data { @@ -226,6 +327,9 @@ struct btrace_data /* Format == BTRACE_FORMAT_PT. */ struct btrace_data_pt pt; + + /* Format == BTRACE_FORMAT_ETM. */ + struct btrace_data_etm etm; } variant; private: -- 2.25.1