/** * Counts a lines in manifest file. Skips commented out and blank lines. * * @param buf * @return */ static int count_mf_lines(jchar* buf) { int numberOfLines = 0; if ((!buf) || (!*buf)) { return -1; } while (*buf) { /* skip commented out lines and lines that start with space */ if ((COMMENTED_OUT(buf)) || (MF_SPACE(buf))) { /* run to the end of line */ while (!NEW_LINE(buf)) { buf++; } /* skip all the new line characters an the end of line */ while (NEW_LINE(buf)) { buf++; } } else { numberOfLines++; while (!NEW_LINE(buf)) { buf++; } while (NEW_LINE(buf)) { buf++; } } } /* end of while */ return numberOfLines; } /* end of count_mf_lines */
/** * Reads a line from a jad file. * * @param jadbuf pointer to the jad jchar_buffer; this pointer will move to * the next line * @param result pointer to pcsl_string where the new line from jad file * will be stored, the caller is responsible for freeing this * string * @return error code */ static MIDPError readJadLine(jchar** jadbuf, pcsl_string * result) { jchar* lineStart = NULL; jchar* p = NULL; int count = 0; /* will use p to avoid all the *(*jadbuf) stuff and make it more readable */ p = (*jadbuf); if (!(*p)) { /* end of jchar_buffer */ *result = PCSL_STRING_NULL; return END_OF_JAD; } /* skip commented out and blank lines */ while (COMMENTED_OUT(p) || NEW_LINE(p)) { while (!NEW_LINE(p)) { /* skip commented out line */ p++; } while (NEW_LINE(p)) { /* skip new line */ p++; } } lineStart = p; for (;*p ; ) { count++; p++; if (NEW_LINE(p)) { *p = 0x00; /* cut the line */ if (*(p+1)) { /* if not end of jchar_buffer */ p++; /* point to the next line beginning */ break; } /* end of if */ } /* end of if */ } /* end of for */ /* move jadbuf to point to the next line */ (*jadbuf) = p; if (PCSL_STRING_OK != pcsl_string_convert_from_utf16(lineStart, count, result)) { return OUT_OF_MEMORY; } return ALL_OK; } /* end of readJadLine */
/** * Reads a line from a manifest file. Compacts continuation lines.<BR> * (Allocates memory for this line.) * * @param mfbuf pointer to the manifest jchar_buffer; this pointer will move to * the next line * @param result pointer to pcsl_string where the new line from manifest * will be stored * @return error code */ static MIDPError readMfLine(jchar** mfbuf, pcsl_string * result) { jchar* lineStart = NULL; int is_broken_line = 0; jchar* p = NULL; int count = 0; int i = 0; *result = PCSL_STRING_NULL; /* will use p to avoid all the *(*mfbuf) stuff and make it more readable */ p = (*mfbuf); if (!(*p)) { /* end of jchar_buffer */ return END_OF_MF; } /* skip commented out and blank lines */ while (COMMENTED_OUT(p) || NEW_LINE(p)) { while (!NEW_LINE(p)) { p++; /* skip commented out line */ } while (NEW_LINE(p)) { p++; /* skip new line */ } /* now pointing to the next line */ if (MF_SPACE(p)) { /* if starting with space */ while (!NEW_LINE(p)) { p++; /* skip the line */ } } /* end of if */ } /* end of while */ lineStart = p; for (;*p ;) { count++; p++; if (NEW_LINE(p) && !MF_BROKEN_LINE(p)) { *p = 0x00; /* cut the line */ if (*(p+1)) { /* if not end of the buffer */ p++; /* point to the next line beginning */ break; } } else if (MF_BROKEN_LINE(p)) { while (!MF_SPACE(p)) { /* look for the space */ count++; p++; } /* once space found, point to the next character and go ahead */ count++; p++; is_broken_line = 1; continue; } /* end of else */ } /* end of for */ /* move mfbuf to point to the next line */ (*mfbuf) = p; pcsl_string_predict_size(result, count); if (is_broken_line) { i = 0; while (*(lineStart+i)) { /* here once we have a new line it will be followed by space */ if (NEW_LINE_1(lineStart+i)) { i+=3; count-=3; } else if (NEW_LINE(lineStart+i)) { i+=2; count-=2; } if (PCSL_STRING_OK != pcsl_string_append_char(result, lineStart[i])) { pcsl_string_free(result); return OUT_OF_MEMORY; } i++; } } else { if (PCSL_STRING_OK != pcsl_string_convert_from_utf16(lineStart, count, result)) { return OUT_OF_MEMORY; } } return ALL_OK; } /* end of readMfLine */
int dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines) { if (unlikely (cudie == NULL || INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit)) return -1; int res = -1; /* Get the information if it is not already known. */ struct Dwarf_CU *const cu = cudie->cu; if (cu->lines == NULL) { /* Failsafe mode: no data found. */ cu->lines = (void *) -1l; cu->files = (void *) -1l; /* The die must have a statement list associated. */ Dwarf_Attribute stmt_list_mem; Dwarf_Attribute *stmt_list = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &stmt_list_mem); /* Get the offset into the .debug_line section. NB: this call also checks whether the previous dwarf_attr call failed. */ Dwarf_Word offset; if (INTUSE(dwarf_formudata) (stmt_list, &offset) != 0) goto out; Dwarf *dbg = cu->dbg; if (dbg->sectiondata[IDX_debug_line] == NULL) { __libdw_seterrno (DWARF_E_NO_DEBUG_LINE); goto out; } const uint8_t *linep = dbg->sectiondata[IDX_debug_line]->d_buf + offset; const uint8_t *lineendp = (dbg->sectiondata[IDX_debug_line]->d_buf + dbg->sectiondata[IDX_debug_line]->d_size); /* Get the compilation directory. */ Dwarf_Attribute compdir_attr_mem; Dwarf_Attribute *compdir_attr = INTUSE(dwarf_attr) (cudie, DW_AT_comp_dir, &compdir_attr_mem); const char *comp_dir = INTUSE(dwarf_formstring) (compdir_attr); if (unlikely (linep + 4 > lineendp)) { invalid_data: __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE); goto out; } Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep); unsigned int length = 4; if (unlikely (unit_length == DWARF3_LENGTH_64_BIT)) { if (unlikely (linep + 8 > lineendp)) goto invalid_data; unit_length = read_8ubyte_unaligned_inc (dbg, linep); length = 8; } /* Check whether we have enough room in the section. */ if (unit_length < 2 + length + 5 * 1 || unlikely (linep + unit_length > lineendp)) goto invalid_data; lineendp = linep + unit_length; /* The next element of the header is the version identifier. */ uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep); if (unlikely (version > DWARF_VERSION)) { __libdw_seterrno (DWARF_E_VERSION); goto out; } /* Next comes the header length. */ Dwarf_Word header_length; if (length == 4) header_length = read_4ubyte_unaligned_inc (dbg, linep); else header_length = read_8ubyte_unaligned_inc (dbg, linep); const unsigned char *header_start = linep; /* Next the minimum instruction length. */ uint_fast8_t minimum_instr_len = *linep++; /* Then the flag determining the default value of the is_stmt register. */ uint_fast8_t default_is_stmt = *linep++; /* Now the line base. */ int_fast8_t line_base = *((int_fast8_t *) linep); ++linep; /* And the line range. */ uint_fast8_t line_range = *linep++; /* The opcode base. */ uint_fast8_t opcode_base = *linep++; /* Remember array with the standard opcode length (-1 to account for the opcode with value zero not being mentioned). */ const uint8_t *standard_opcode_lengths = linep - 1; linep += opcode_base - 1; if (unlikely (linep >= lineendp)) goto invalid_data; /* First comes the list of directories. Add the compilation directory first since the index zero is used for it. */ struct dirlist { const char *dir; size_t len; struct dirlist *next; } comp_dir_elem = { .dir = comp_dir, .len = comp_dir ? strlen (comp_dir) : 0, .next = NULL }; struct dirlist *dirlist = &comp_dir_elem; unsigned int ndirlist = 1; // XXX Directly construct array to conserve memory? while (*linep != 0) { struct dirlist *new_dir = (struct dirlist *) alloca (sizeof (*new_dir)); new_dir->dir = (char *) linep; uint8_t *endp = memchr (linep, '\0', lineendp - linep); if (endp == NULL) goto invalid_data; new_dir->len = endp - linep; new_dir->next = dirlist; dirlist = new_dir; ++ndirlist; linep = endp + 1; } /* Skip the final NUL byte. */ ++linep; /* Rearrange the list in array form. */ struct dirlist **dirarray = (struct dirlist **) alloca (ndirlist * sizeof (*dirarray)); for (unsigned int n = ndirlist; n-- > 0; dirlist = dirlist->next) dirarray[n] = dirlist; /* Now read the files. */ struct filelist null_file = { .info = { .name = "???", .mtime = 0, .length = 0 }, .next = NULL }; struct filelist *filelist = &null_file; unsigned int nfilelist = 1; if (unlikely (linep >= lineendp)) goto invalid_data; while (*linep != 0) { struct filelist *new_file = (struct filelist *) alloca (sizeof (*new_file)); /* First comes the file name. */ char *fname = (char *) linep; uint8_t *endp = memchr (fname, '\0', lineendp - linep); if (endp == NULL) goto invalid_data; size_t fnamelen = endp - (uint8_t *) fname; linep = endp + 1; /* Then the index. */ Dwarf_Word diridx; get_uleb128 (diridx, linep); if (unlikely (diridx >= ndirlist)) { __libdw_seterrno (DWARF_E_INVALID_DIR_IDX); goto out; } if (*fname == '/') /* It's an absolute path. */ new_file->info.name = fname; else { new_file->info.name = libdw_alloc (dbg, char, 1, dirarray[diridx]->len + 1 + fnamelen + 1); char *cp = new_file->info.name; if (dirarray[diridx]->dir != NULL) { /* This value could be NULL in case the DW_AT_comp_dir was not present. We cannot do much in this case. The easiest thing is to convert the path in an absolute path. */ cp = stpcpy (cp, dirarray[diridx]->dir); } *cp++ = '/'; strcpy (cp, fname); assert (strlen (new_file->info.name) < dirarray[diridx]->len + 1 + fnamelen + 1); } /* Next comes the modification time. */ get_uleb128 (new_file->info.mtime, linep); /* Finally the length of the file. */ get_uleb128 (new_file->info.length, linep); new_file->next = filelist; filelist = new_file; ++nfilelist; } /* Skip the final NUL byte. */ ++linep; /* Consistency check. */ if (unlikely (linep != header_start + header_length)) { __libdw_seterrno (DWARF_E_INVALID_DWARF); goto out; } /* We are about to process the statement program. Initialize the state machine registers (see 6.2.2 in the v2.1 specification). */ Dwarf_Word address = 0; size_t file = 1; size_t line = 1; size_t column = 0; uint_fast8_t is_stmt = default_is_stmt; int basic_block = 0; int prologue_end = 0; int epilogue_begin = 0; /* Process the instructions. */ struct linelist *linelist = NULL; unsigned int nlinelist = 0; while (linep < lineendp) { struct linelist *new_line; unsigned int opcode; unsigned int u128; int s128; /* Read the opcode. */ opcode = *linep++; /* Is this a special opcode? */ if (likely (opcode >= opcode_base)) { /* Yes. Handling this is quite easy since the opcode value is computed with opcode = (desired line increment - line_base) + (line_range * address advance) + opcode_base */ int line_increment = (line_base + (opcode - opcode_base) % line_range); unsigned int address_increment = (minimum_instr_len * ((opcode - opcode_base) / line_range)); /* Perform the increments. */ line += line_increment; address += address_increment; /* Add a new line with the current state machine values. */ NEW_LINE (0); /* Reset the flags. */ basic_block = 0; prologue_end = 0; epilogue_begin = 0; } else if (opcode == 0) { /* This an extended opcode. */ if (unlikely (linep + 2 > lineendp)) goto invalid_data; /* The length. */ unsigned int len = *linep++; if (unlikely (linep + len > lineendp)) goto invalid_data; /* The sub-opcode. */ opcode = *linep++; switch (opcode) { case DW_LNE_end_sequence: /* Add a new line with the current state machine values. The is the end of the sequence. */ NEW_LINE (1); /* Reset the registers. */ address = 0; file = 1; line = 1; column = 0; is_stmt = default_is_stmt; basic_block = 0; prologue_end = 0; epilogue_begin = 0; break; case DW_LNE_set_address: /* The value is an address. The size is defined as apporiate for the target machine. We use the address size field from the CU header. */ if (cu->address_size == 4) address = read_4ubyte_unaligned_inc (dbg, linep); else address = read_8ubyte_unaligned_inc (dbg, linep); break; case DW_LNE_define_file: { char *fname = (char *) linep; uint8_t *endp = memchr (linep, '\0', lineendp - linep); if (endp == NULL) goto invalid_data; size_t fnamelen = endp - linep; linep = endp + 1; unsigned int diridx; get_uleb128 (diridx, linep); Dwarf_Word mtime; get_uleb128 (mtime, linep); Dwarf_Word filelength; get_uleb128 (filelength, linep); struct filelist *new_file = (struct filelist *) alloca (sizeof (*new_file)); if (fname[0] == '/') new_file->info.name = fname; else { new_file->info.name = libdw_alloc (dbg, char, 1, (dirarray[diridx]->len + 1 + fnamelen + 1)); char *cp = new_file->info.name; if (dirarray[diridx]->dir != NULL) /* This value could be NULL in case the DW_AT_comp_dir was not present. We cannot do much in this case. The easiest thing is to convert the path in an absolute path. */ cp = stpcpy (cp, dirarray[diridx]->dir); *cp++ = '/'; strcpy (cp, fname); } new_file->info.mtime = mtime; new_file->info.length = filelength; new_file->next = filelist; filelist = new_file; ++nfilelist; } break; default: /* Unknown, ignore it. */ linep += len - 1; break; } } else if (opcode <= DW_LNS_set_epilogue_begin) { /* This is a known standard opcode. */ switch (opcode) { case DW_LNS_copy: /* Takes no argument. */ if (unlikely (standard_opcode_lengths[opcode] != 0)) goto invalid_data; /* Add a new line with the current state machine values. */ NEW_LINE (0); /* Reset the flags. */ basic_block = 0; /* XXX Whether the following two lines are necessary is unclear. I guess the current v2.1 specification has a bug in that it says clearing these two registers is not necessary. */ prologue_end = 0; epilogue_begin = 0; break; case DW_LNS_advance_pc: /* Takes one uleb128 parameter which is added to the address. */ if (unlikely (standard_opcode_lengths[opcode] != 1)) goto invalid_data; get_uleb128 (u128, linep); address += minimum_instr_len * u128; break; case DW_LNS_advance_line: /* Takes one sleb128 parameter which is added to the line. */ if (unlikely (standard_opcode_lengths[opcode] != 1)) goto invalid_data; get_sleb128 (s128, linep); line += s128; break; case DW_LNS_set_file: /* Takes one uleb128 parameter which is stored in file. */ if (unlikely (standard_opcode_lengths[opcode] != 1)) goto invalid_data; get_uleb128 (u128, linep); file = u128; break; case DW_LNS_set_column: /* Takes one uleb128 parameter which is stored in column. */ if (unlikely (standard_opcode_lengths[opcode] != 1)) goto invalid_data; get_uleb128 (u128, linep); column = u128; break; case DW_LNS_negate_stmt: /* Takes no argument. */ if (unlikely (standard_opcode_lengths[opcode] != 0)) goto invalid_data; is_stmt = 1 - is_stmt; break; case DW_LNS_set_basic_block: /* Takes no argument. */ if (unlikely (standard_opcode_lengths[opcode] != 0)) goto invalid_data; basic_block = 1; break; case DW_LNS_const_add_pc: /* Takes no argument. */ if (unlikely (standard_opcode_lengths[opcode] != 0)) goto invalid_data; address += (minimum_instr_len * ((255 - opcode_base) / line_range)); break; case DW_LNS_fixed_advance_pc: /* Takes one 16 bit parameter which is added to the address. */ if (unlikely (standard_opcode_lengths[opcode] != 1)) goto invalid_data; address += read_2ubyte_unaligned_inc (dbg, linep); break; case DW_LNS_set_prologue_end: /* Takes no argument. */ if (unlikely (standard_opcode_lengths[opcode] != 0)) goto invalid_data; prologue_end = 1; break; case DW_LNS_set_epilogue_begin: /* Takes no argument. */ if (unlikely (standard_opcode_lengths[opcode] != 0)) goto invalid_data; epilogue_begin = 1; break; } } else { /* This is a new opcode the generator but not we know about. Read the parameters associated with it but then discard everything. Read all the parameters for this opcode. */ for (int n = standard_opcode_lengths[opcode]; n > 0; --n) get_uleb128 (u128, linep); /* Next round, ignore this opcode. */ continue; } }