1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
|
/*
Copyright (C) 2000-2006 Silicon Graphics, Inc. All Rights Reserved.
Portions Copyright 2007-2010 Sun Microsystems, Inc. All rights reserved.
Portions Copyright 2009-2018 SN Systems Ltd. All rights reserved.
Portions Copyright 2008-2020 David Anderson. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the terms of version 2 of the GNU General
Public License as published by the Free Software Foundation.
This program is distributed in the hope that it would be
useful, but WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.
Further, this software is distributed without any warranty
that it is free of the rightful claim of any third person
regarding infringement or the like. Any license provided
herein, whether implied or otherwise, applies only to this
software file. Patent licenses, if any, provided herein
do not apply to combinations of this program with other
software, or any other product whatsoever.
You should have received a copy of the GNU General Public
License along with this program; if not, write the Free
Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston MA 02110-1301, USA.
*/
#include "globals.h"
#include "esb.h"
#include "esb_using_functions.h"
#include "sanitized.h"
static struct esb_s esb_string;
void
ranges_esb_string_destructor(void)
{
esb_destructor(&esb_string);
}
/* Because we do not know what DIE is involved, if the
object being printed has different address sizes
in different compilation units this will not work
properly: anything could happen. */
extern int
print_ranges(Dwarf_Debug dbg,
UNUSEDARG Dwarf_Error *err)
{
Dwarf_Unsigned off = 0;
int group_number = 0;
int wasdense = 0;
struct esb_s truename;
char buf[DWARF_SECNAME_BUFFER_SIZE];
unsigned loopct = 0;
glflags.current_section_id = DEBUG_RANGES;
if (!glflags.gf_do_print_dwarf) {
return DW_DLV_OK;
}
esb_constructor_fixed(&truename,buf,sizeof(buf));
/* Turn off dense, we do not want print_ranges_list_to_extra
to use dense form here. */
wasdense = glflags.dense;
glflags.dense = 0;
for (;;++loopct) {
Dwarf_Ranges *rangeset = 0;
Dwarf_Signed rangecount = 0;
Dwarf_Unsigned bytecount = 0;
Dwarf_Error pr_err;
/* We do not know what DIE is involved, we use
the older call here. */
int rres = dwarf_get_ranges(dbg,off,&rangeset,
&rangecount,&bytecount,&pr_err);
if (!loopct) {
get_true_section_name(dbg,".debug_ranges",
&truename,TRUE);
printf("\n%s\n",sanitized(esb_get_string(&truename)));
}
if (rres == DW_DLV_OK) {
char *val = 0;
printf(" Ranges group %d:\n",group_number);
esb_empty_string(&esb_string);
print_ranges_list_to_extra(dbg,off,off,
rangeset,rangecount,bytecount,
&esb_string);
dwarf_ranges_dealloc(dbg,rangeset,rangecount);
val = esb_get_string(&esb_string);
printf("%s",sanitized(val));
++group_number;
} else if (rres == DW_DLV_NO_ENTRY) {
printf("End of %s.\n",sanitized(esb_get_string(&truename)));
break;
} else {
/* ERROR, which does not quite mean a real error,
as we might just be misaligned reading things without
a DW_AT_ranges offset.*/
struct esb_s m;
esb_constructor(&m);
esb_append_printf_u(&m,"ERROR: at offset 0x%lx in ",off);
esb_append_printf_s(&m,"section %s. Stopping ranges"
" output.",sanitized(esb_get_string(&truename)));
print_error_and_continue(dbg,esb_get_string(&m),
rres,pr_err);
dwarf_dealloc(dbg,pr_err,DW_DLA_ERROR);
pr_err = 0;
esb_destructor(&m);
break;
}
off += bytecount;
}
glflags.dense = wasdense;
esb_destructor(&truename);
return DW_DLV_OK;
}
/* Extracted this from print_range_attribute() to isolate the check of
the range list.
*/
static int
check_ranges_list(Dwarf_Debug dbg,
UNUSEDARG Dwarf_Off die_off,
Dwarf_Die cu_die,
Dwarf_Unsigned original_off,
Dwarf_Unsigned finaloff,
Dwarf_Ranges *rangeset,
Dwarf_Signed rangecount,
Dwarf_Unsigned bytecount,
Dwarf_Error *err)
{
Dwarf_Unsigned off = original_off;
Dwarf_Signed index = 0;
Dwarf_Addr base_address = glflags.CU_base_address;
Dwarf_Addr lopc = 0;
Dwarf_Addr hipc = 0;
Dwarf_Bool bError = FALSE;
Dwarf_Half elf_address_size = 0;
Dwarf_Addr elf_max_address = 0;
static boolean do_print = TRUE;
const char *sec_name = 0;
struct esb_s truename;
char buf[DWARF_SECNAME_BUFFER_SIZE];
esb_constructor_fixed(&truename,buf,sizeof(buf));
get_true_section_name(dbg,".debug_ranges",
&truename,FALSE);
sec_name = esb_get_string(&truename);
get_address_size_and_max(dbg,&elf_address_size,&elf_max_address,err);
/* Ignore last entry, is the end-of-list */
for (index = 0; index < rangecount - 1; index++) {
Dwarf_Ranges *r = rangeset + index;
if (r->dwr_addr1 == elf_max_address) {
/* (0xffffffff,addr), use specific address (current PU address) */
base_address = r->dwr_addr2;
} else {
/* (offset,offset), update using CU address */
lopc = r->dwr_addr1 + base_address;
hipc = r->dwr_addr2 + base_address;
DWARF_CHECK_COUNT(ranges_result,1);
/* Check the low_pc and high_pc
are within a valid range in
the .text section */
if (IsValidInBucketGroup(glflags.pRangesInfo,lopc) &&
IsValidInBucketGroup(glflags.pRangesInfo,hipc)) {
/* Valid values; do nothing */
} else {
/* At this point may be we
are dealing with a
linkonce symbol */
if (IsValidInLinkonce(glflags.pLinkonceInfo,
glflags.PU_name,lopc,hipc)) {
/* Valid values; do nothing */
} else {
struct esb_s errbuf;
bError = TRUE;
esb_constructor(&errbuf);
esb_append_printf_s(&errbuf,
"%s: Address outside a "
"valid .text range",sanitized(sec_name));
DWARF_CHECK_ERROR(ranges_result,
esb_get_string(&errbuf));
esb_destructor(&errbuf);
if (glflags.gf_check_verbose_mode && do_print) {
/* Update DIEs offset just for printing */
int dioff_res = dwarf_die_offsets(cu_die,
&glflags.DIE_overall_offset,
&glflags.DIE_offset,err);
if (dioff_res != DW_DLV_OK) {
simple_err_return_msg_either_action(
dioff_res,
"Call to dwarf_die_offsets failed "
"for the CU DIE."
"in printing ranges");
return dioff_res;
}
printf(
"Offset = 0x%" DW_PR_XZEROS DW_PR_DUx
", Base = 0x%" DW_PR_XZEROS DW_PR_DUx
", "
"Low = 0x%" DW_PR_XZEROS DW_PR_DUx
" (0x%" DW_PR_XZEROS DW_PR_DUx
"), High = 0x%"
DW_PR_XZEROS DW_PR_DUx
" (0x%" DW_PR_XZEROS DW_PR_DUx
")\n",
off,base_address,lopc,
r->dwr_addr1,hipc,
r->dwr_addr2);
}
}
}
}
/* Each entry holds 2 addresses (offsets) */
off += elf_address_size * 2;
}
/* In the case of errors, we have to print the range records that
caused the error. */
if (bError && glflags.gf_check_verbose_mode && do_print) {
struct esb_s rangesstr;
esb_constructor(&rangesstr);
printf("\n");
print_ranges_list_to_extra(dbg,original_off,
finaloff,
rangeset,rangecount,bytecount,
&rangesstr);
printf("%s\n", sanitized(esb_get_string(&rangesstr)));
esb_destructor(&rangesstr);
}
/* In the case of printing unique errors, stop the printing of any
subsequent errors, which have the same text. */
if (bError && glflags.gf_check_verbose_mode &&
glflags.gf_print_unique_errors) {
do_print = FALSE;
}
esb_destructor(&truename);
return DW_DLV_OK;
}
/* Records information about compilers (producers) found in the
debug information, including the check results for several
categories (see -k option). */
typedef struct {
Dwarf_Off die_off;
Dwarf_Off range_off;
} Range_Array_Entry;
/* Array to record the DW_AT_range attribute DIE, to be used at the end
of the CU, to check the range values; DWARF4 allows an offset relative
to the low_pc as the high_pc value. Also, LLVM generates for the CU the
pair (low_pc, at_ranges) instead of the traditional (low_pc, high_pc).
*/
static Range_Array_Entry *range_array = NULL;
static Dwarf_Unsigned range_array_size = 0;
static Dwarf_Unsigned range_array_count = 0;
#define RANGE_ARRAY_INITIAL_SIZE 64
/* Allocate space to store information about the ranges; the values are
extracted from the DW_AT_ranges attribute. The space is reused by all CUs.
*/
void
allocate_range_array_info()
{
if (range_array == NULL) {
/* Allocate initial range array info */
range_array = (Range_Array_Entry *)
calloc(RANGE_ARRAY_INITIAL_SIZE,sizeof(Range_Array_Entry));
range_array_size = RANGE_ARRAY_INITIAL_SIZE;
}
}
void
release_range_array_info()
{
if (range_array) {
free(range_array);
range_array = 0;
range_array_size = 0;
range_array_count = 0;
}
}
/* Clear out values from previous CU */
static void
reset_range_array_info()
{
if (range_array) {
memset((void *)range_array,0,
(range_array_count) * sizeof(Range_Array_Entry));
range_array_count = 0;
}
}
void
record_range_array_info_entry(Dwarf_Off die_off,Dwarf_Off range_off)
{
/* Record a new detected range info. */
if (range_array_count == range_array_size) {
/* Resize range array */
range_array_size *= 2;
range_array = (Range_Array_Entry *)
realloc(range_array,
(range_array_size) * sizeof(Range_Array_Entry));
}
/* The 'die_off' is the Global Die Offset */
range_array[range_array_count].die_off = die_off;
range_array[range_array_count].range_off = range_off;
++range_array_count;
}
/* Now that we are at the end of the CU, check the range lists */
int
check_range_array_info(Dwarf_Debug dbg,Dwarf_Error * err)
{
if (range_array && range_array_count) {
/* Traverse the range array and for each entry:
Load the ranges
Check for any outside conditions */
Dwarf_Off original_off = 0;
Dwarf_Off finaloffset = 0;
Dwarf_Off die_off = 0;
Dwarf_Unsigned index = 0;
Dwarf_Die cu_die = 0;
int res = 0;
/* In case of errors, the correct DIE offset should be
displayed. At this point we are at the end of the PU */
Dwarf_Off DIE_overall_offset_bak = glflags.DIE_overall_offset;
for (index = 0; index < range_array_count; ++index) {
Dwarf_Ranges *rangeset = 0;
Dwarf_Signed rangecount = 0;
Dwarf_Unsigned bytecount = 0;
/* Get a range info record */
die_off = range_array[index].die_off;
original_off = range_array[index].range_off;
res = dwarf_offdie(dbg,die_off,&cu_die,err);
if (res != DW_DLV_OK) {
struct esb_s m;
esb_constructor(&m);
esb_append_printf_u(&m,
"Call to dwarf_offdie failed "
"getting the CU die from offset "
" 0x" DW_PR_XZEROS DW_PR_DUx
"in checking ranges",die_off);
simple_err_return_msg_either_action(
res,
esb_get_string(&m));
esb_destructor(&m);
return res;
}
res = dwarf_get_ranges_b(dbg,original_off,
cu_die,
&finaloffset,
&rangeset,&rangecount,&bytecount,err);
if (res == DW_DLV_OK) {
res = check_ranges_list(dbg,die_off,
cu_die,original_off,finaloffset,
rangeset,rangecount,bytecount,err);
if (res != DW_DLV_OK) {
dwarf_dealloc(dbg,cu_die,DW_DLA_DIE);
reset_range_array_info();
return res;
}
dwarf_dealloc(dbg,rangeset,DW_DLA_RANGES);
}
dwarf_dealloc(dbg,cu_die,DW_DLA_DIE);
};
reset_range_array_info();
/* Point back to the end of the PU */
glflags.DIE_overall_offset = DIE_overall_offset_bak;
}
return DW_DLV_OK;
}
|