From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from nx202.node01.secure-mailgate.com (nx202.node01.secure-mailgate.com [89.22.108.202]) by sourceware.org (Postfix) with ESMTPS id D0FBF384C008 for ; Thu, 11 Mar 2021 02:51:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org D0FBF384C008 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 node01.secure-mailgate.com with esmtps (TLSv1.2:AES128-GCM-SHA256:128) (Exim 4.92) (envelope-from ) id 1lKBPk-00F5J8-2l for gdb-patches@sourceware.org; Thu, 11 Mar 2021 03:51:04 +0100 X-SecureMailgate-Identity: host202.checkdomain.de Received: from Trande0001.fritz.box (x4db421df.dyn.telefonica.de [77.180.33.223]) (Authenticated sender: zied.guermazi@trande.de) by host202.checkdomain.de (Postfix) with ESMTPSA id 655EF2A35DD; Thu, 11 Mar 2021 03:51:03 +0100 (CET) X-SecureMailgate-Identity: host202.checkdomain.de From: Zied Guermazi To: gdb-patches@sourceware.org Cc: Zied Guermazi Subject: [PATCH v2 3/8] start/stop btrace with coresight etm and parse etm buffer. nat independant Date: Thu, 11 Mar 2021 03:50:34 +0100 Message-Id: <20210311025039.57112-4-zied.guermazi@trande.de> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210311025039.57112-1-zied.guermazi@trande.de> References: <20210311025039.57112-1-zied.guermazi@trande.de> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-PPP-Message-ID: <20210311025103.3192022.31325@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 (3.02830871562e-06) X-Recommended-Action: accept X-Filter-ID: Pt3MvcO5N4iKaDQ5O6lkdGlMVN6RH8bjRMzItlySaT+Lc7t9W1ABeTzTImcdoIVZPUtbdvnXkggZ 3YnVId/Y5jcf0yeVQAvfjHznO7+bT5wgSQOko5ya3orWH1MkzQXa2oPZqVS5i0KNMNtVCi0tRw/C h5SE4jAyhe1COeASyU9h6M1nW5bpoKAVQrogqy2u4ld5rdi2ZxohSIq+dqifZqZB0VgKyzk1hxKn NCROVogVZjUFgdVrb53pIBbvvIldBVisGv8MyVI5ms3guyJnGh/34QJ1h9PdtL0qz0e/tKoUOled bu+r9+W9cDXvzL3SKMADmSgTOnv22Aeeug8bgxUePrEkthz/AkjSL3YY1rc+AwMXi+OSqQVvJeAt QeT9Q5MeWyHYFcw5tP/0jE4kl2Vgy64k7VOKE8LGVSqZUUeGBm2F2ZSc/GphP5KHuWIVyGcCgytU Mu2J9HJXA1Uo4GK9rNXrMwoTWcjWHnwp/pypDdbUeVhhRSNmbtZhZo/4pw1Bi8ttLThN67lnnreq FYljc3cdkir05kMDTgrRv8/dAGQ93WWVSHcYlg6mr/IfPd0rEuGjFyZoidhtHm+WoZN0yPT2Goo4 tfV2y4t+PaCzOVXCPWfYkC8dRIZCBp73D1e76szsWvBsaS+KViusBg4TfS2su/byymSuqTyxp/ZE xDyRiioQmvGTre37mWh0chGFHjQ6q190o7vmaHflc956nYunM0LAws9BZvWchghPpTsikaWr8agN x6i+pTHOV0S4zXCZWClBlEPVbO974G6DF4QTrQ9BNA+/r3OeYI6oKQ3OTMzavSIUpRjMaax7LOjr OwwGI3kKu05JnDlv7i2KaYxSU3oP8eSYKFMX9MC+9+EAydx4ZblaPQ0vNSRxuT8vn+rN4dX3VsVy R5CI/dKys9znVbnNj5tlwcuQYubebj5PgIM/J5G71lWEqRatbLzQ9rMYGFaZaGZsj3e0MASlKrTU IyM54V6ZtlUTKBfDqcigOvSxdRnthmhn8Zn6weR83xvb4QCeqR85K3X4rVfWaPHLh9d13TvnYIJS 8uss0ueeSQv3iRNCdtD1uwyAKMADmSgTOnv22Aeeug8bgwJPDDg1BsZlJJwIRfFRTyc2vKtsh88u M6zHbDccOKMrUoTh9tkkYGx1qtbnIjA6A3MtdZ3kU7K9G0Sx0xT0TSw= X-Report-Abuse-To: spam@node04.secure-mailgate.com X-Spam-Status: No, score=-9.5 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, RCVD_IN_BARRACUDACENTRAL, 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: Thu, 11 Mar 2021 02:51:10 -0000 This patch extend branch tracing by adding the functions needed to collect parameters for decoding ETM traces and decoding them. 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 | 27 +- gdb/btrace.c | 621 +++++++++++++++++++++++++++++++++++- gdb/btrace.h | 25 ++ gdb/record-btrace.c | 20 +- gdbsupport/ChangeLog | 13 + gdbsupport/btrace-common.cc | 42 ++- gdbsupport/btrace-common.h | 147 ++++++++- 7 files changed, 886 insertions(+), 9 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a63fdfa1911..4453a3e8185 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,28 @@ +2021-02-25 Zied Guermazi + + * 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 + 2021-02-25 Zied Guermazi * record-btrace.c (record_btrace_print_etm_conf): New. @@ -9,7 +34,7 @@ (_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..4d1bd96379e 100644 --- a/gdb/btrace.c +++ b/gdb/btrace.c @@ -42,6 +42,7 @@ #include #include #include +#include "arch/arm.h" /* Command lists for btrace maintenance commands. */ static struct cmd_list_element *maint_btrace_cmdlist; @@ -227,6 +228,24 @@ 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 +276,8 @@ 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 +692,36 @@ 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) +{ + /* If we didn't have a function, we return. */ + if (btinfo->functions.empty ()) + return; + + struct btrace_function *bfun; + bfun = &btinfo->functions.back (); + /* If we had a gap before, we return. */ + if (bfun->errcode != 0) + return; + + if (!bfun->insn.empty ()) + bfun->insn.pop_back (); + else + { + /* A valid function must have at least one insn. */ + internal_error (__FILE__, __LINE__, + _("Attempt to remove last instruction from an empty function")); + } +} +#endif /* defined (HAVE_LIBOPENCSD_C_API) */ + /* Classify the instruction at PC. */ static enum btrace_insn_class @@ -1193,7 +1244,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 +1553,557 @@ btrace_compute_ftrace_pt (struct thread_info *tp, #endif /* defined (HAVE_LIBIPT) */ +#if defined (HAVE_LIBOPENCSD_C_API) + +/* This structure holds the status and the context for decoding ETM traces. +It is also used in the ETM trace element callback to get the context. */ +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; +} + +/* 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) +{ + gdb_assert (elem->elem_type == OCSD_GEN_TRC_ELEM_INSTR_RANGE); + + struct cs_etm_decoder *etm_decoder; + etm_decoder = (struct cs_etm_decoder *) context; + if (etm_decoder->t_info == nullptr) + return; + + struct thread_info *tp; + tp = etm_decoder->t_info; + + struct btrace_thread_info *btinfo; + btinfo = &tp->btrace; + + struct gdbarch *gdbarch; + gdbarch = target_gdbarch (); + + struct btrace_insn insn; + CORE_ADDR pc; + int size; + 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.")); + } + + struct btrace_function *bfun; + bfun = ftrace_update_function (btinfo, pc); + insn.iclass=BTRACE_INSN_OTHER; + insn.size = size; + if (etm_decoder->arch_version == ARCH_V7) + { + unsigned int cpsr; + 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; + } + struct record_btrace_reg_entry reg; + 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) +{ + gdb_assert (elem->elem_type == OCSD_GEN_TRC_ELEM_EXCEPTION); + + struct cs_etm_decoder *etm_decoder; + etm_decoder = (struct cs_etm_decoder *) context; + if (etm_decoder->t_info == nullptr) + return; + + struct thread_info *tp; + tp = etm_decoder->t_info; + + struct btrace_thread_info *btinfo; + 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->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) +{ + gdb_assert (elem->elem_type == OCSD_GEN_TRC_ELEM_TRACE_ON); + + struct cs_etm_decoder *etm_decoder; + etm_decoder = (struct cs_etm_decoder *)context; + if (etm_decoder->t_info == nullptr) + return; + + struct thread_info *tp; + tp = etm_decoder->t_info; + + struct btrace_thread_info *btinfo; + btinfo = &tp->btrace; + + 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); + + 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 OCSD_RESP_CONT; +} + +/* 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; + 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; + DEBUG ("cs_etm_create_decoder: Unknown architecture version"); + return false; + + } + uint8_t csid; + if (ocsd_dt_create_decoder (decoder->dcd_tree, decoder_name, + OCSD_CREATE_FLG_FULL_DECODER, + trace_config, &csid)) + { + DEBUG ("ocsd_dt_create_decoder failed"); + return false; + } + + if (ocsd_dt_set_gen_elem_outfn (decoder->dcd_tree, + cs_etm_trace_element_callback, + decoder)) + { + DEBUG ("ocsd_dt_set_gen_elem_outfn failed"); + 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) +{ + ocsd_dcd_tree_src_t src_type = OCSD_TRC_SRC_SINGLE; + uint32_t deformatterCfgFlags = 0; + + 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; + + dcd_tree_handle_t dcdtree_handle; + dcdtree_handle = ocsd_create_dcd_tree (src_type, deformatterCfgFlags); + + if (dcdtree_handle == C_API_INVALID_TREE_HANDLE) + { + DEBUG ("ocsd_create_dcd_tree failed"); + return nullptr; + } + struct cs_etm_decoder *decoder; + + decoder = (struct cs_etm_decoder*) xmalloc (sizeof (struct cs_etm_decoder)); + decoder->dcd_tree = dcdtree_handle; + + bool ret; + for (int i = 0; i < num_cpu; i++) + { + ret = cs_etm_create_decoder (&(t_params->at (i)), decoder); + if (ret == false) + { + DEBUG ("cs_etm_create_decoder failed"); + ocsd_destroy_dcd_tree (decoder->dcd_tree); + free (decoder); + return nullptr; + } + + } + decoder->t_info = tp; + return decoder; +} + +/* Free a cs_etm_decoder. */ + +static void +cs_etm_free_decoder (struct cs_etm_decoder *decoder) +{ + if (decoder == nullptr) + return; + + ocsd_destroy_dcd_tree (decoder->dcd_tree); + decoder->dcd_tree = nullptr; + decoder->t_info = nullptr; + 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, nullptr, nullptr); + } 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) +{ + for (const btrace_function &function : btinfo->functions) + ftrace_debug (&function, ""); +} + +static void +btrace_compute_ftrace_etm (struct thread_info *tp, + const struct btrace_data_etm *btrace, + std::vector &gaps) +{ + DEBUG_FTRACE ("btrace->size is 0x%x for thread %s", + (unsigned int)(btrace->size), print_thread_id (tp)); + if (btrace->size == 0) + return; + + struct btrace_thread_info *btinfo; + btinfo = &tp->btrace; + if (btinfo->functions.empty ()) + btinfo->level = 0; + + struct cs_etm_decoder *decoder; + decoder = cs_etm_alloc_decoder (tp,btrace->config.num_cpu, + btrace->config.etm_decoder_params, + btrace->config.etm_trace_params); + if (decoder == nullptr) + error (_("Failed to allocate ARM CoreSight ETM Trace decoder.")); + + ocsd_err_t ocsd_error; + 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.")); + + int errcode; + size_t consumed; + 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 +2133,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 +2205,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 +2401,10 @@ 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 +4027,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) */ } } diff --git a/gdb/btrace.h b/gdb/btrace.h index 8f6ce32103d..168be5488a2 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,22 @@ 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 +{ + /* Register number. */ + unsigned short num; + + /* Register size in sizeof (gdb_byte). */ + unsigned short len; + + /* Buffer for storing register value. */ + 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 +96,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 4d6495d440d..cf15a90f543 100644 --- a/gdb/record-btrace.c +++ b/gdb/record-btrace.c @@ -1576,18 +1576,29 @@ record_btrace_target::fetch_registers (struct regcache *regcache, int regno) struct gdbarch *gdbarch; int pcreg; + insn = btrace_insn_get (replay); + gdb_assert (insn != nullptr); + 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 +3031,6 @@ cmd_record_btrace_start (const char *args, int from_tty) } } - /* The "show record btrace replay-memory-access" command. */ static void diff --git a/gdbsupport/ChangeLog b/gdbsupport/ChangeLog index ed4708b7028..38dc5a79277 100644 --- a/gdbsupport/ChangeLog +++ b/gdbsupport/ChangeLog @@ -1,3 +1,16 @@ +2021-02-25 Zied Guermazi + + * 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. + 2021-02-25 Zied Guermazi * btrace-common.h (btrace_format): add BTRACE_FORMAT_ETM diff --git a/gdbsupport/btrace-common.cc b/gdbsupport/btrace-common.cc index 461f769ed51..9dc94d32470 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 != nullptr) + 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 = nullptr; + 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 4ac658b9946..103a674763a 100644 --- a/gdbsupport/btrace-common.h +++ b/gdbsupport/btrace-common.h @@ -159,7 +159,6 @@ struct btrace_config /* The ARM CoreSight ETM Trace configuration. */ struct btrace_config_etm etm; - }; /* Branch trace in BTS format. */ @@ -191,6 +190,149 @@ 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 +{ + /* ETMv3 Main Control Register. */ + uint32_t reg_ctrl; + + /* ETMv3 Trace ID Register. */ + uint32_t reg_trc_id; + + /* ETMv3 Configuration Code Extension Register. */ + uint32_t reg_ccer; + + /* ETMv3 ID Register. */ + 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 +{ + /* ETMv4 ID Register 0. */ + uint32_t reg_idr0; + + /* ETMv4 ID Register 1. */ + uint32_t reg_idr1; + + /* ETMv4 ID Register 2. */ + uint32_t reg_idr2; + + /* ETMv4 ID Register 8. */ + uint32_t reg_idr8; + + /* ETMv4 Config Register. */ + uint32_t reg_configr; + + /* ETMv4 Trace ID Register. */ + uint32_t reg_traceidr; +}; + +/* The following enums are indexed starting with 1 to align with the + open source coresight trace decoder library (opencsd). */ +enum +{ + /* Traces in ETMV3 protocol. */ + CS_ETM_PROTO_ETMV3 = 1, + + /* Traces in ETMV4 instructions protocol. */ + CS_ETM_PROTO_ETMV4i, + + /* Traces in ETMV4 data protocol. */ + CS_ETM_PROTO_ETMV4d, + + /* Traces in PTM protocol. */ + CS_ETM_PROTO_PTM, +}; + +/* The following enum must be aligned with the + open source coresight trace decoder library (opencsd). */ + +/* Core Architecture Version. */ +enum +{ + /* unknown architecture. */ + ARCHITECTURE_UNKNOWN, + + /* None ARM, custom architecture. */ + ARCHITECTURE_CUSTOM, + + /* V7 architecture. */ + ARCHITECTURE_V7, + + /* V8 architecture. */ + ARCHITECTURE_V8, + + /* V8.3 architecture. */ + ARCHITECTURE_V8r3, +}; + +/* 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, /* Formatted input, or single source input. */ + fsyncs :1, /* Formatted data has fsyncs. */ + hsyncs :1, /* Formatted data has hsyncs. */ + frame_aligned :1, /* Formatted frames are memory aligned. */ + reset_on_4x_sync :1, /* Reset decoders at 4x consecutive fsyncs. */ + __res :3; /* Reserved, not used. */ +}; + +/* 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 { @@ -228,6 +370,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