From patchwork Thu Mar 12 20:05:03 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Evans X-Patchwork-Id: 5596 Received: (qmail 99440 invoked by alias); 12 Mar 2015 20:05:11 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 99424 invoked by uid 89); 12 Mar 2015 20:05:10 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.7 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW, SPF_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mail-ob0-f202.google.com Received: from mail-ob0-f202.google.com (HELO mail-ob0-f202.google.com) (209.85.214.202) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Thu, 12 Mar 2015 20:05:06 +0000 Received: by obbnt9 with SMTP id nt9so4697818obb.0 for ; Thu, 12 Mar 2015 13:05:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:cc:date:message-id:mime-version :content-type; bh=/jb4yIbTdmJmoDww6jSNR04eRDcv+dmRPVN6kAJ7m6I=; b=cjqvScR+q98LL4dz0Z3C+F89auccSXSxJBWsNx3p6lG+sq0u8/XeIsSkJX2O2wYFHa 4xOtDGd4aehTXA2v04/Gs0cQ/QAxOvnJe4VZyuQpedVqUmdrTf4UQwaQG4V0DMd2U01r l+b5jPlZY11v4CzsmsYdvJGlWk+34Pz9BaBfeof+s75CTzHiqDjac38yTRwGjKwm/i1D 8NqJQrhCNHx4vLfgRFwGtJA4A4Fnoi3YW6l7o42X+fJdrz2wa9n7L0RSY3g5i7+djVh2 yjgbYzoE0L7g4lPWoQsOwmnmRkr8sC5BIkmo8ksi6iPtCjRu+316P0d0JG49AmszT8eT DBug== X-Gm-Message-State: ALoCoQmGLjx2aFsEebvDgbihNjSlNv0LAsIHljXOaASnk9ElqDRFzsLQpc8pRuch5akKUH0d0ebY X-Received: by 10.50.61.132 with SMTP id p4mr67666908igr.7.1426190704228; Thu, 12 Mar 2015 13:05:04 -0700 (PDT) Received: from corpmail-nozzle1-1.hot.corp.google.com ([100.108.1.104]) by gmr-mx.google.com with ESMTPS id k10si420990yho.2.2015.03.12.13.05.03 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 12 Mar 2015 13:05:04 -0700 (PDT) Received: from ruffy.mtv.corp.google.com ([172.17.128.44]) by corpmail-nozzle1-1.hot.corp.google.com with ESMTPS id TcF7CiLx.1; Thu, 12 Mar 2015 13:05:03 -0700 From: Doug Evans To: gdb-patches@sourceware.org Subject: [PATCH 4/6] DWARF Two Level Line Tables: lnp_state_machine, lnp_reader_state cc: ccoutant@google.com Date: Thu, 12 Mar 2015 13:05:03 -0700 Message-ID: MIME-Version: 1.0 X-IsSubscribed: yes Hi. This patch puts the line number state machine into a struct to make it clear exactly what is part of the state machine and what is not. Previously, gdb just had a bunch of local variables. 2015-03-12 Doug Evans * dwarf2read.c (lnp_state_machine): New typedef. (lnp_reader_state): New typedef. (dwarf_record_line_1): Renamed from dwarf_record_line. All callers updated. (dwarf_record_line): New function. (init_lnp_state_machine): New function. (check_line_address): Replace p_record_line parameter with state. All callers updated. (dwarf_decode_lines_1): Call dwarf_record_line, init_lnp_state_machine. Update to record state in lnp_state_machine. diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index fff5474..827ae6c 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -17434,6 +17434,54 @@ psymtab_include_file_name (const struct line_header *lh, int file_index, typedef void (record_line_ftype) (struct subfile *subfile, int line, CORE_ADDR pc); +/* State machine to track the state of the line number program. */ + +typedef struct +{ + /* These are part of the standard DWARF line number state machine. */ + + unsigned char op_index; + unsigned int file; + unsigned int line; + CORE_ADDR address; + int is_stmt; + unsigned int discriminator; + + /* Additional bits of state we need to track. */ + + /* The last file that we called dwarf2_start_subfile for. + This is only used for TLLs. */ + unsigned int last_file; + /* The last file a line number was recorded for. */ + struct subfile *last_subfile; + + /* The function to call to record a line. */ + record_line_ftype *record_line; + + /* The last line number that was recorded, used to coalesce + consecutive entries for the same line. This can happen, for + example, when discriminators are present. PR 17276. */ + unsigned int last_line; + int line_has_non_zero_discriminator; +} lnp_state_machine; + +/* There's a lot of static state to pass to dwarf_record_line. + This keeps it all together. */ + +typedef struct +{ + /* The gdbarch. */ + struct gdbarch *gdbarch; + + /* The line number header. */ + struct line_header *line_header; + + /* Non-zero if we're recording lines. + Otherwise we're building partial symtabs and are just interested in + finding include files mentioned by the line number program. */ + int record_lines_p; +} lnp_reader_state; + /* Ignore this record_line request. */ static void @@ -17493,9 +17541,9 @@ dwarf_record_line_p (unsigned int line, unsigned int last_line, in the line table of subfile SUBFILE. */ static void -dwarf_record_line (struct gdbarch *gdbarch, struct subfile *subfile, - unsigned int line, CORE_ADDR address, - record_line_ftype p_record_line) +dwarf_record_line_1 (struct gdbarch *gdbarch, struct subfile *subfile, + unsigned int line, CORE_ADDR address, + record_line_ftype p_record_line) { CORE_ADDR addr = gdbarch_addr_bits_remove (gdbarch, address); @@ -17512,7 +17560,7 @@ dwarf_record_line (struct gdbarch *gdbarch, struct subfile *subfile, /* Subroutine of dwarf_decode_lines_1 to simplify it. Mark the end of a set of line number records. - The arguments are the same as for dwarf_record_line. + The arguments are the same as for dwarf_record_line_1. If SUBFILE is NULL the request is ignored. */ static void @@ -17530,14 +17578,105 @@ dwarf_finish_line (struct gdbarch *gdbarch, struct subfile *subfile, paddress (gdbarch, address)); } - dwarf_record_line (gdbarch, subfile, 0, address, p_record_line); + dwarf_record_line_1 (gdbarch, subfile, 0, address, p_record_line); +} + +/* Record either a logical line or an actual line. + END_SEQUENCE is non-zero if we're processing the end of a sequence. */ + +static void +dwarf_record_line (lnp_reader_state *reader, lnp_state_machine *state, + int end_sequence) +{ + const struct line_header *lh = reader->line_header; + unsigned int file, line, discriminator; + int is_stmt; + + file = state->file; + line = state->line; + is_stmt = state->is_stmt; + discriminator = state->discriminator; + + if (dwarf2_line_debug) + { + fprintf_unfiltered (gdb_stdlog, + "Processing actual line %u: file %u," + " address %s, is_stmt %u, discrim %u\n", + line, file, + paddress (reader->gdbarch, state->address), + is_stmt, discriminator); + } + + if (file == 0 || file - 1 >= lh->num_file_names) + dwarf2_debug_line_missing_file_complaint (); + /* For now we ignore lines not starting on an instruction boundary. + But not when processing end_sequence for compatibility with the + previous version of the code. */ + else if (state->op_index == 0 || end_sequence) + { + lh->file_names[file - 1].included_p = 1; + if (reader->record_lines_p && is_stmt) + { + if (state->last_subfile != current_subfile) + { + dwarf_finish_line (reader->gdbarch, state->last_subfile, + state->address, state->record_line); + } + + if (!end_sequence) + { + if (dwarf_record_line_p (line, state->last_line, + state->line_has_non_zero_discriminator, + state->last_subfile)) + { + dwarf_record_line_1 (reader->gdbarch, current_subfile, + line, state->address, + state->record_line); + } + state->last_subfile = current_subfile; + state->last_line = line; + } + } + } +} + +/* Initialize STATE for the start of a line number program. + TODO(dje): Seems like this should be reset at the start of each sequence + but that's not what the previous code did. */ + +static void +init_lnp_state_machine (lnp_state_machine *state, + const lnp_reader_state *reader) +{ + memset (state, 0, sizeof (*state)); + + /* Just starting, there is no "last file". */ + state->last_file = 0; + state->last_subfile = NULL; + + state->record_line = record_line; + + state->last_line = 0; + state->line_has_non_zero_discriminator = 0; + + /* Initialize these according to the DWARF spec. */ + state->op_index = 0; + state->file = 1; + state->line = 1; + /* Call `gdbarch_adjust_dwarf2_line' on the initial 0 address as if there + was a line entry for it so that the backend has a chance to adjust it + and also record it in case it needs it. This is currently used by MIPS + code, cf. `mips_adjust_dwarf2_line'. */ + state->address = gdbarch_adjust_dwarf2_line (reader->gdbarch, 0, 0); + state->is_stmt = reader->line_header->default_is_stmt; + state->discriminator = 0; } /* Check address and if invalid nop-out the rest of the lines in this sequence. */ static void -check_line_address (struct dwarf2_cu *cu, record_line_ftype **p_record_line, +check_line_address (struct dwarf2_cu *cu, lnp_state_machine *state, const gdb_byte *line_ptr, CORE_ADDR lowpc, CORE_ADDR address) { @@ -17557,14 +17696,16 @@ check_line_address (struct dwarf2_cu *cu, record_line_ftype **p_record_line, complaint (&symfile_complaints, _(".debug_line address at offset 0x%lx is 0 [in module %s]"), line_offset, objfile_name (objfile)); - *p_record_line = noop_record_line; - /* Note: *p_record_line is left as noop_record_line + state->record_line = noop_record_line; + /* Note: sm.record_line is left as noop_record_line until we see DW_LNE_end_sequence. */ } } /* Subroutine of dwarf_decode_lines to simplify it. - Process the line number information in LH. */ + Process the line number information in LH. + If DECODE_FOR_PST_P is non-zero, all we do is process the line number + program in order to set included_p for every referenced header. */ static void dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, @@ -17578,43 +17719,38 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, struct objfile *objfile = cu->objfile; bfd *abfd = objfile->obfd; struct gdbarch *gdbarch = get_objfile_arch (objfile); - struct subfile *last_subfile = NULL; - void (*p_record_line) (struct subfile *subfile, int line, CORE_ADDR pc) - = record_line; + /* Non-zero if we're recording line info (as opposed to building partial + symtabs or building the logical line table). */ + int record_lines_p = !decode_for_pst_p; + /* A collection of things we need to pass to dwarf_record_line. */ + lnp_reader_state reader_state; baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); line_ptr = lh->statement_program_start; line_end = lh->statement_program_end; + reader_state.gdbarch = gdbarch; + reader_state.line_header = lh; + reader_state.record_lines_p = record_lines_p; + /* Read the statement sequences until there's nothing left. */ while (line_ptr < line_end) { - /* State machine registers. Call `gdbarch_adjust_dwarf2_line' - on the initial 0 address as if there was a line entry for it - so that the backend has a chance to adjust it and also record - it in case it needs it. This is currently used by MIPS code, - cf. `mips_adjust_dwarf2_line'. */ - CORE_ADDR address = gdbarch_adjust_dwarf2_line (gdbarch, 0, 0); - unsigned int file = 1; - unsigned int line = 1; - int is_stmt = lh->default_is_stmt; + /* The DWARF line number program state machine. */ + lnp_state_machine state_machine; int end_sequence = 0; - unsigned char op_index = 0; - unsigned int discriminator = 0; - /* The last line number that was recorded, used to coalesce - consecutive entries for the same line. This can happen, for - example, when discriminators are present. PR 17276. */ - unsigned int last_line = 0; - int line_has_non_zero_discriminator = 0; - - if (!decode_for_pst_p && lh->num_file_names >= file) + + /* Reset the state machine at the start of each sequence. */ + init_lnp_state_machine (&state_machine, &reader_state); + + if (record_lines_p && lh->num_file_names >= state_machine.file) { /* Start a subfile for the current file of the state machine. */ /* lh->include_dirs and lh->file_names are 0-based, but the directory and file name numbers in the statement program are 1-based. */ - struct file_entry *fe = &lh->file_names[file - 1]; + struct file_entry *fe = &lh->file_names[state_machine.file - 1]; const char *dir = NULL; if (fe->dir_index) @@ -17624,15 +17760,10 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, } /* Decode the table. */ - while (!end_sequence) + while (line_ptr < line_end && !end_sequence) { op_code = read_1_byte (abfd, line_ptr); line_ptr += 1; - if (line_ptr > line_end) - { - dwarf2_debug_line_missing_end_sequence_complaint (); - break; - } if (op_code >= lh->opcode_base) { @@ -17642,42 +17773,23 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, int line_delta; adj_opcode = op_code - lh->opcode_base; - addr_adj = (((op_index + (adj_opcode / lh->line_range)) + addr_adj = (((state_machine.op_index + + (adj_opcode / lh->line_range)) / lh->maximum_ops_per_instruction) * lh->minimum_instruction_length); - address += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1); - op_index = ((op_index + (adj_opcode / lh->line_range)) - % lh->maximum_ops_per_instruction); + state_machine.address + += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1); + state_machine.op_index = ((state_machine.op_index + + (adj_opcode / lh->line_range)) + % lh->maximum_ops_per_instruction); line_delta = lh->line_base + (adj_opcode % lh->line_range); - line += line_delta; + state_machine.line += line_delta; if (line_delta != 0) - line_has_non_zero_discriminator = discriminator != 0; - if (lh->num_file_names < file || file == 0) - dwarf2_debug_line_missing_file_complaint (); - /* For now we ignore lines not starting on an - instruction boundary. */ - else if (op_index == 0) - { - lh->file_names[file - 1].included_p = 1; - if (!decode_for_pst_p && is_stmt) - { - if (last_subfile != current_subfile) - { - dwarf_finish_line (gdbarch, last_subfile, - address, p_record_line); - } - if (dwarf_record_line_p (line, last_line, - line_has_non_zero_discriminator, - last_subfile)) - { - dwarf_record_line (gdbarch, current_subfile, - line, address, p_record_line); - } - last_subfile = current_subfile; - last_line = line; - } - } - discriminator = 0; + state_machine.line_has_non_zero_discriminator + = state_machine.discriminator != 0; + + dwarf_record_line (&reader_state, &state_machine, 0); + state_machine.discriminator = 0; } else switch (op_code) { @@ -17691,17 +17803,22 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, switch (extended_op) { case DW_LNE_end_sequence: - p_record_line = record_line; + state_machine.record_line = record_line; end_sequence = 1; break; case DW_LNE_set_address: - address = read_address (abfd, line_ptr, cu, &bytes_read); - line_ptr += bytes_read; - check_line_address (cu, &p_record_line, line_ptr, - lowpc, address); - op_index = 0; - address += baseaddr; - address = gdbarch_adjust_dwarf2_line (gdbarch, address, 0); + { + CORE_ADDR address + = read_address (abfd, line_ptr, cu, &bytes_read); + + line_ptr += bytes_read; + check_line_address (cu, &state_machine, line_ptr, + lowpc, address); + state_machine.op_index = 0; + address += baseaddr; + state_machine.address + = gdbarch_adjust_dwarf2_line (gdbarch, address, 0); + } break; case DW_LNE_define_file: { @@ -17729,9 +17846,10 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, if there are consecutive entries for the same (non-prologue) line we want to coalesce them. PR 17276. */ - discriminator = read_unsigned_leb128 (abfd, line_ptr, - &bytes_read); - line_has_non_zero_discriminator |= discriminator != 0; + state_machine.discriminator + = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + state_machine.line_has_non_zero_discriminator + |= state_machine.discriminator != 0; line_ptr += bytes_read; break; default: @@ -17750,30 +17868,8 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, } break; case DW_LNS_copy: - if (lh->num_file_names < file || file == 0) - dwarf2_debug_line_missing_file_complaint (); - else - { - lh->file_names[file - 1].included_p = 1; - if (!decode_for_pst_p && is_stmt) - { - if (last_subfile != current_subfile) - { - dwarf_finish_line (gdbarch, last_subfile, - address, p_record_line); - } - if (dwarf_record_line_p (line, last_line, - line_has_non_zero_discriminator, - last_subfile)) - { - dwarf_record_line (gdbarch, current_subfile, - line, address, p_record_line); - } - last_subfile = current_subfile; - last_line = line; - } - } - discriminator = 0; + dwarf_record_line (&reader_state, &state_machine, 0); + state_machine.discriminator = 0; break; case DW_LNS_advance_pc: { @@ -17781,12 +17877,13 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); CORE_ADDR addr_adj; - addr_adj = (((op_index + adjust) + addr_adj = (((state_machine.op_index + adjust) / lh->maximum_ops_per_instruction) * lh->minimum_instruction_length); - address += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1); - op_index = ((op_index + adjust) - % lh->maximum_ops_per_instruction); + state_machine.address + += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1); + state_machine.op_index = ((state_machine.op_index + adjust) + % lh->maximum_ops_per_instruction); line_ptr += bytes_read; } break; @@ -17795,9 +17892,10 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, int line_delta = read_signed_leb128 (abfd, line_ptr, &bytes_read); - line += line_delta; + state_machine.line += line_delta; if (line_delta != 0) - line_has_non_zero_discriminator = discriminator != 0; + state_machine.line_has_non_zero_discriminator + = state_machine.discriminator != 0; line_ptr += bytes_read; } break; @@ -17809,19 +17907,22 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, struct file_entry *fe; const char *dir = NULL; - file = read_unsigned_leb128 (abfd, line_ptr, &bytes_read); + state_machine.file = read_unsigned_leb128 (abfd, line_ptr, + &bytes_read); line_ptr += bytes_read; - if (lh->num_file_names < file || file == 0) + if (state_machine.file == 0 + || state_machine.file - 1 >= lh->num_file_names) dwarf2_debug_line_missing_file_complaint (); else { - fe = &lh->file_names[file - 1]; + fe = &lh->file_names[state_machine.file - 1]; if (fe->dir_index) - dir = lh->include_dirs[fe->dir_index - 1]; - if (!decode_for_pst_p) + dir = lh->include_dirs[fe->dir_index - 1]; + if (record_lines_p) { - last_subfile = current_subfile; - line_has_non_zero_discriminator = discriminator != 0; + state_machine.last_subfile = current_subfile; + state_machine.line_has_non_zero_discriminator + = state_machine.discriminator != 0; dwarf2_start_subfile (fe->name, dir); } } @@ -17832,7 +17933,7 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, line_ptr += bytes_read; break; case DW_LNS_negate_stmt: - is_stmt = (!is_stmt); + state_machine.is_stmt = (!state_machine.is_stmt); break; case DW_LNS_set_basic_block: break; @@ -17846,12 +17947,13 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, CORE_ADDR adjust = (255 - lh->opcode_base) / lh->line_range; CORE_ADDR addr_adj; - addr_adj = (((op_index + adjust) + addr_adj = (((state_machine.op_index + adjust) / lh->maximum_ops_per_instruction) * lh->minimum_instruction_length); - address += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1); - op_index = ((op_index + adjust) - % lh->maximum_ops_per_instruction); + state_machine.address + += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1); + state_machine.op_index = ((state_machine.op_index + adjust) + % lh->maximum_ops_per_instruction); } break; case DW_LNS_fixed_advance_pc: @@ -17859,8 +17961,9 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, CORE_ADDR addr_adj; addr_adj = read_2_bytes (abfd, line_ptr); - address += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1); - op_index = 0; + state_machine.address + += gdbarch_adjust_dwarf2_line (gdbarch, addr_adj, 1); + state_machine.op_index = 0; line_ptr += 2; } break; @@ -17877,17 +17980,13 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu, } } } - if (lh->num_file_names < file || file == 0) - dwarf2_debug_line_missing_file_complaint (); - else - { - lh->file_names[file - 1].included_p = 1; - if (!decode_for_pst_p) - { - dwarf_finish_line (gdbarch, current_subfile, address, - p_record_line); - } - } + + if (!end_sequence) + dwarf2_debug_line_missing_end_sequence_complaint (); + + /* We got a DW_LNE_end_sequence (or we ran off the end of the buffer, + in which case we still finish recording the last line). */ + dwarf_record_line (&reader_state, &state_machine, 1); } }