From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 5722 invoked by alias); 18 Dec 2009 19:46:28 -0000 Received: (qmail 5714 invoked by uid 22791); 18 Dec 2009 19:46:27 -0000 X-SWARE-Spam-Status: No, hits=-1.5 required=5.0 tests=AWL,BAYES_00,KAM_STOCKGEN,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 18 Dec 2009 19:46:21 +0000 Received: (qmail 863 invoked from network); 18 Dec 2009 19:46:20 -0000 Received: from unknown (HELO macbook-2.local) (stan@127.0.0.2) by mail.codesourcery.com with ESMTPA; 18 Dec 2009 19:46:20 -0000 Message-ID: <4B2BDC02.9010209@codesourcery.com> Date: Fri, 18 Dec 2009 19:46:00 -0000 From: Stan Shebs User-Agent: Thunderbird 2.0.0.23 (Macintosh/20090812) MIME-Version: 1.0 To: gdb-patches Subject: [PATCH] Handle LOC_COMPUTED variables in tracepoint actions Content-Type: multipart/mixed; boundary="------------020408090607080005010406" Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2009-12/txt/msg00265.txt.bz2 This is a multi-part message in MIME format. --------------020408090607080005010406 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 1500 The last time that anybody used tracepoints much, stabs was still the norm and Dwarf 2 the newbie, and so nobody thought much about handling variables with computed locations. Nowadays many local variables have computed locations, and we have to generate appropriate agent expression bytecodes. Worse, the top-level encoding machinery for tracepoint actions will issue instructions to collect variables directly, not using bytecodes, so we need to detect when bytecodes are necessary. (In theory we could always generate bytecodes for collection expressions; that would make a good cleanup for later.) This patch doesn't handle every possible computed location, that's a big project of its own (basically translating arbitrary dwarf2 bytecode sequences into equivalent agent expression bytecodes), it just handles frame/base register combinations that are typical for local vars. Even the simplified version is a little arcane, so I'll leave it up for comments for a few days before committing. Stan 2009-12-18 Stan Shebs * ax-gdb.h (gen_trace_for_var): Declare. * ax-gdb.c (gen_trace_for_var): New function. * dwarf2loc.c (dwarf_expr_frame_base_1): New function, split from... (dwarf_expr_frame_base): ...here. (dwarf2_tracepoint_var_ref): Add computed location case. * tracepoint.c (collect_symbol): Add scope arg and LOC_COMPUTED case. (add_local_symbols): Update call to collect_symbol. (encode_actions): Ditto. --------------020408090607080005010406 Content-Type: text/plain; x-mac-type="0"; x-mac-creator="0"; name="loccomp-patch-1" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="loccomp-patch-1" Content-length: 9221 Index: ax-gdb.c =================================================================== RCS file: /cvs/src/src/gdb/ax-gdb.c,v retrieving revision 1.53 diff -p -r1.53 ax-gdb.c *** ax-gdb.c 14 Jul 2009 21:40:30 -0000 1.53 --- ax-gdb.c 18 Dec 2009 19:27:46 -0000 *************** gen_expr (struct expression *exp, union *** 1768,1773 **** --- 1768,1797 ---- } + struct agent_expr * + gen_trace_for_var (CORE_ADDR scope, struct symbol *var) + { + struct cleanup *old_chain = 0; + struct agent_expr *ax = new_agent_expr (scope); + struct axs_value value; + + old_chain = make_cleanup_free_agent_expr (ax); + + trace_kludge = 1; + gen_var_ref (NULL, ax, &value, var); + + /* Make sure we record the final object, and get rid of it. */ + gen_traced_pop (ax, &value); + + /* Oh, and terminate. */ + ax_simple (ax, aop_end); + + /* We have successfully built the agent expr, so cancel the cleanup + request. If we add more cleanups that we always want done, this + will have to get more complicated. */ + discard_cleanups (old_chain); + return ax; + } /* Generating bytecode from GDB expressions: driver */ Index: ax-gdb.h =================================================================== RCS file: /cvs/src/src/gdb/ax-gdb.h,v retrieving revision 1.12 diff -p -r1.12 ax-gdb.h *** ax-gdb.h 14 Jul 2009 21:40:30 -0000 1.12 --- ax-gdb.h 18 Dec 2009 19:27:46 -0000 *************** struct axs_value *** 99,104 **** --- 99,106 ---- function to discover which registers the expression uses. */ extern struct agent_expr *gen_trace_for_expr (CORE_ADDR, struct expression *); + extern struct agent_expr *gen_trace_for_var (CORE_ADDR, struct symbol *); + extern struct agent_expr *gen_eval_for_expr (CORE_ADDR, struct expression *); #endif /* AX_GDB_H */ Index: dwarf2loc.c =================================================================== RCS file: /cvs/src/src/gdb/dwarf2loc.c,v retrieving revision 1.68 diff -p -r1.68 dwarf2loc.c *** dwarf2loc.c 15 Sep 2009 16:20:53 -0000 1.68 --- dwarf2loc.c 18 Dec 2009 19:27:46 -0000 *************** *** 41,46 **** --- 41,50 ---- #include "gdb_string.h" #include "gdb_assert.h" + static void + dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc, + gdb_byte **start, size_t * length); + /* A helper function for dealing with location lists. Given a symbol baton (BATON) and a pc value (PC), find the appropriate location expression, set *LOCEXPR_LENGTH, and return a pointer *************** dwarf_expr_frame_base (void *baton, gdb_ *** 166,181 **** something has gone wrong. */ gdb_assert (framefunc != NULL); if (SYMBOL_LOCATION_BATON (framefunc) == NULL) *start = NULL; else if (SYMBOL_COMPUTED_OPS (framefunc) == &dwarf2_loclist_funcs) { struct dwarf2_loclist_baton *symbaton; - struct frame_info *frame = debaton->frame; symbaton = SYMBOL_LOCATION_BATON (framefunc); ! *start = find_location_expression (symbaton, length, ! get_frame_address_in_block (frame)); } else { --- 170,192 ---- something has gone wrong. */ gdb_assert (framefunc != NULL); + dwarf_expr_frame_base_1 (framefunc, + get_frame_address_in_block (debaton->frame), + start, length); + } + + static void + dwarf_expr_frame_base_1 (struct symbol *framefunc, CORE_ADDR pc, + gdb_byte **start, size_t * length) + { if (SYMBOL_LOCATION_BATON (framefunc) == NULL) *start = NULL; else if (SYMBOL_COMPUTED_OPS (framefunc) == &dwarf2_loclist_funcs) { struct dwarf2_loclist_baton *symbaton; symbaton = SYMBOL_LOCATION_BATON (framefunc); ! *start = find_location_expression (symbaton, length, pc); } else { *************** dwarf2_tracepoint_var_ref (struct symbol *** 617,637 **** } else if (data[0] == DW_OP_fbreg) { ! /* And this is worse than just minimal; we should honor the frame base ! as above. */ ! int frame_reg; LONGEST frame_offset; gdb_byte *buf_end; buf_end = read_sleb128 (data + 1, data + size, &frame_offset); if (buf_end != data + size) error (_("Unexpected opcode after DW_OP_fbreg for symbol \"%s\"."), SYMBOL_PRINT_NAME (symbol)); - gdbarch_virtual_frame_pointer (gdbarch, - ax->scope, &frame_reg, &frame_offset); ax_reg (ax, frame_reg); ! ax_const_l (ax, frame_offset); ax_simple (ax, aop_add); value->kind = axs_lvalue_memory; --- 628,679 ---- } else if (data[0] == DW_OP_fbreg) { ! struct block *b; ! struct symbol *framefunc; ! int frame_reg = 0; LONGEST frame_offset; gdb_byte *buf_end; + gdb_byte *base_data; + size_t base_size; + LONGEST base_offset = 0; + + b = block_for_pc (ax->scope); + + if (!b) + error (_("No block found for address")); + + framefunc = block_linkage_function (b); + + if (!framefunc) + error (_("No function found for block")); + + dwarf_expr_frame_base_1 (framefunc, ax->scope, + &base_data, &base_size); + + if (base_data[0] >= DW_OP_breg0 + && base_data[0] <= DW_OP_breg31) + { + frame_reg = base_data[0] - DW_OP_breg0; + buf_end = read_sleb128 (base_data + 1, base_data + base_size, &base_offset); + if (buf_end != base_data + base_size) + error (_("Unexpected opcode after DW_OP_breg%u for symbol \"%s\"."), + frame_reg, SYMBOL_PRINT_NAME (symbol)); + } + else + { + /* We don't know what to do with the frame base expression, + so we can't trace this variable; give up. */ + error (_("Cannot generate expression to collect symbol \"%s\"."), + SYMBOL_PRINT_NAME (symbol)); + } buf_end = read_sleb128 (data + 1, data + size, &frame_offset); if (buf_end != data + size) error (_("Unexpected opcode after DW_OP_fbreg for symbol \"%s\"."), SYMBOL_PRINT_NAME (symbol)); ax_reg (ax, frame_reg); ! ax_const_l (ax, base_offset + frame_offset); ax_simple (ax, aop_add); value->kind = axs_lvalue_memory; Index: tracepoint.c =================================================================== RCS file: /cvs/src/src/gdb/tracepoint.c,v retrieving revision 1.126 diff -p -r1.126 tracepoint.c *** tracepoint.c 14 Jul 2009 21:40:30 -0000 1.126 --- tracepoint.c 18 Dec 2009 19:27:46 -0000 *************** static void *** 725,731 **** collect_symbol (struct collection_list *collect, struct symbol *sym, struct gdbarch *gdbarch, ! long frame_regno, long frame_offset) { unsigned long len; unsigned int reg; --- 725,732 ---- collect_symbol (struct collection_list *collect, struct symbol *sym, struct gdbarch *gdbarch, ! long frame_regno, long frame_offset, ! CORE_ADDR scope) { unsigned long len; unsigned int reg; *************** collect_symbol (struct collection_list * *** 817,822 **** --- 818,867 ---- printf_filtered ("%s has been optimized out of existence.\n", SYMBOL_PRINT_NAME (sym)); break; + + case LOC_COMPUTED: + { + struct agent_expr *aexpr; + struct cleanup *old_chain1 = NULL; + struct agent_reqs areqs; + + aexpr = gen_trace_for_var (scope, sym); + + old_chain1 = make_cleanup_free_agent_expr (aexpr); + + ax_reqs (aexpr, &areqs); + if (areqs.flaw != agent_flaw_none) + error (_("malformed expression")); + + if (areqs.min_height < 0) + error (_("gdb: Internal error: expression has min height < 0")); + if (areqs.max_height > 20) + error (_("expression too complicated, try simplifying")); + + discard_cleanups (old_chain1); + add_aexpr (collect, aexpr); + + /* take care of the registers */ + if (areqs.reg_mask_len > 0) + { + int ndx1, ndx2; + + for (ndx1 = 0; ndx1 < areqs.reg_mask_len; ndx1++) + { + QUIT; /* allow user to bail out with ^C */ + if (areqs.reg_mask[ndx1] != 0) + { + /* assume chars have 8 bits */ + for (ndx2 = 0; ndx2 < 8; ndx2++) + if (areqs.reg_mask[ndx1] & (1 << ndx2)) + /* it's used -- record it */ + add_register (collect, + ndx1 * 8 + ndx2); + } + } + } + } + break; } } *************** add_local_symbols (struct collection_lis *** 843,849 **** { count++; collect_symbol (collect, sym, gdbarch, ! frame_regno, frame_offset); } } if (BLOCK_FUNCTION (block)) --- 888,894 ---- { count++; collect_symbol (collect, sym, gdbarch, ! frame_regno, frame_offset, pc); } } if (BLOCK_FUNCTION (block)) *************** encode_actions (struct breakpoint *t, ch *** 1122,1128 **** exp->elts[2].symbol, t->gdbarch, frame_reg, ! frame_offset); break; default: /* full-fledged expression */ --- 1167,1174 ---- exp->elts[2].symbol, t->gdbarch, frame_reg, ! frame_offset, ! t->loc->address); break; default: /* full-fledged expression */ --------------020408090607080005010406--