 */
static void php_wddx_serialize_array(wddx_packet *packet, zval *arr)
{
	zval *ent;
	zend_string *key;
	int is_struct = 0;
	zend_ulong idx;
	HashTable *target_hash;
	char tmp_buf[WDDX_BUF_LEN];
	zend_ulong ind = 0;

	target_hash = Z_ARRVAL_P(arr);
	ZEND_HASH_FOREACH_KEY(target_hash, idx, key) {
		if (key) {
			is_struct = 1;
			break;
		}

		if (idx != ind) {
			is_struct = 1;
			break;
		}
		ind++;
	} ZEND_HASH_FOREACH_END();

	if (is_struct) {
		php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
	} else {
		snprintf(tmp_buf, sizeof(tmp_buf), WDDX_ARRAY_S, zend_hash_num_elements(target_hash));
		php_wddx_add_chunk(packet, tmp_buf);
	}

	ZEND_HASH_FOREACH_KEY_VAL(target_hash, idx, key, ent) {
		if (ent == arr) {
			continue;
		}

		if (is_struct) {
			if (key) {
				php_wddx_serialize_var(packet, ent, key);
			} else {
				key = zend_long_to_str(idx);
				php_wddx_serialize_var(packet, ent, key);
				zend_string_release(key);
			}
		} else {
			php_wddx_serialize_var(packet, ent, NULL);
		}
	} ZEND_HASH_FOREACH_END();

	if (is_struct) {
		php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
	} else {
		php_wddx_add_chunk_static(packet, WDDX_ARRAY_E);
	}


Fix for bug #72790 and bug #72799

(cherry picked from commit a14fdb9746262549bbbb96abb87338bacd147e1b)

Conflicts:
	ext/wddx/wddx.c

 */
static void php_wddx_serialize_object(wddx_packet *packet, zval *obj)
{
/* OBJECTS_FIXME */
	zval *ent, fname, *varname;
	zval retval;
	zend_string *key;
	zend_ulong idx;
	char tmp_buf[WDDX_BUF_LEN];
	HashTable *objhash, *sleephash;

	ZVAL_STRING(&fname, "__sleep");
	/*
	 * We try to call __sleep() method on object. It's supposed to return an
	 * array of property names to be serialized.
	 */
	if (call_user_function_ex(CG(function_table), obj, &fname, &retval, 0, 0, 1, NULL) == SUCCESS) {
		if (!Z_ISUNDEF(retval) && (sleephash = HASH_OF(&retval))) {
			PHP_CLASS_ATTRIBUTES;

			PHP_SET_CLASS_ATTRIBUTES(obj);

			php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
			snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
			php_wddx_add_chunk(packet, tmp_buf);
			php_wddx_add_chunk_static(packet, WDDX_STRING_S);
			php_wddx_add_chunk_ex(packet, ZSTR_VAL(class_name), ZSTR_LEN(class_name));
			php_wddx_add_chunk_static(packet, WDDX_STRING_E);
			php_wddx_add_chunk_static(packet, WDDX_VAR_E);

			PHP_CLEANUP_CLASS_ATTRIBUTES();

			objhash = Z_OBJPROP_P(obj);

			ZEND_HASH_FOREACH_VAL(sleephash, varname) {
				if (Z_TYPE_P(varname) != IS_STRING) {
					php_error_docref(NULL, E_NOTICE, "__sleep should return an array only containing the names of instance-variables to serialize.");
					continue;
				}

				if ((ent = zend_hash_find(objhash, Z_STR_P(varname))) != NULL) {
					php_wddx_serialize_var(packet, ent, Z_STR_P(varname));
				}
			} ZEND_HASH_FOREACH_END();

			php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
		}
	} else {
		PHP_CLASS_ATTRIBUTES;

		PHP_SET_CLASS_ATTRIBUTES(obj);

		php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);
		snprintf(tmp_buf, WDDX_BUF_LEN, WDDX_VAR_S, PHP_CLASS_NAME_VAR);
		php_wddx_add_chunk(packet, tmp_buf);
		php_wddx_add_chunk_static(packet, WDDX_STRING_S);
		php_wddx_add_chunk_ex(packet, ZSTR_VAL(class_name), ZSTR_LEN(class_name));
		php_wddx_add_chunk_static(packet, WDDX_STRING_E);
		php_wddx_add_chunk_static(packet, WDDX_VAR_E);

		PHP_CLEANUP_CLASS_ATTRIBUTES();

		objhash = Z_OBJPROP_P(obj);
		ZEND_HASH_FOREACH_KEY_VAL(objhash, idx, key, ent) {
			if (ent == obj) {
				continue;
			}
			if (key) {
				const char *class_name, *prop_name;
				size_t prop_name_len;
				zend_string *tmp;

				zend_unmangle_property_name_ex(key, &class_name, &prop_name, &prop_name_len);
				tmp = zend_string_init(prop_name, prop_name_len, 0);
				php_wddx_serialize_var(packet, ent, tmp);
				zend_string_release(tmp);
			} else {
				key = zend_long_to_str(idx);
				php_wddx_serialize_var(packet, ent, key);
				zend_string_release(key);
			}
		} ZEND_HASH_FOREACH_END();
		php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
	}

	zval_ptr_dtor(&fname);
	zval_ptr_dtor(&retval);

ext/wddx/wddx.c in PHP before 5.6.25 and 7.x before 7.0.10 allows remote attackers to cause a denial of service (NULL pointer dereference and application crash) or possibly have unspecified other impact via an invalid wddxPacket XML document that is mishandled in a wddx_deserialize call, as demonstrated by a stray element inside a boolean element, leading to incorrect pop processing.


 */
void php_wddx_packet_start(wddx_packet *packet, char *comment, size_t comment_len)
{
	php_wddx_add_chunk_static(packet, WDDX_PACKET_S);
	if (comment) {
		zend_string *escaped = php_escape_html_entities(
			comment, comment_len, 0, ENT_QUOTES, NULL);

		php_wddx_add_chunk_static(packet, WDDX_HEADER_S);
		php_wddx_add_chunk_static(packet, WDDX_COMMENT_S);
		php_wddx_add_chunk_ex(packet, ZSTR_VAL(escaped), ZSTR_LEN(escaped));
		php_wddx_add_chunk_static(packet, WDDX_COMMENT_E);
		php_wddx_add_chunk_static(packet, WDDX_HEADER_E);

		zend_string_release(escaped);
	} else {
		php_wddx_add_chunk_static(packet, WDDX_HEADER);
	}
	php_wddx_add_chunk_static(packet, WDDX_DATA_S);


 */
static void php_wddx_process_data(void *user_data, const XML_Char *s, int len)
{
	st_entry *ent;
	wddx_stack *stack = (wddx_stack *)user_data;

	if (!wddx_stack_is_empty(stack) && !stack->done) {
		wddx_stack_top(stack, (void**)&ent);
		switch (ent->type) {
			case ST_BINARY:
			case ST_STRING:
				if (Z_STRLEN(ent->data) == 0) {
					zval_ptr_dtor(&ent->data);
					ZVAL_STRINGL(&ent->data, (char *)s, len);
				} else {
					Z_STR(ent->data) = zend_string_extend(Z_STR(ent->data), Z_STRLEN(ent->data) + len, 0);
					memcpy(Z_STRVAL(ent->data) + Z_STRLEN(ent->data) - len, (char *)s, len);
					Z_STRVAL(ent->data)[Z_STRLEN(ent->data)] = '\0';
				}
				break;
			case ST_NUMBER:
				ZVAL_STRINGL(&ent->data, (char *)s, len);
				convert_scalar_to_number(&ent->data);
				break;

			case ST_BOOLEAN:
				if (!strcmp((char *)s, "true")) {
					ZVAL_TRUE(&ent->data);
				} else if (!strcmp((char *)s, "false")) {
					ZVAL_FALSE(&ent->data);
				} else {
					zval_ptr_dtor(&ent->data);
					if (ent->varname) {
						efree(ent->varname);
						ent->varname = NULL;
					}
					ZVAL_UNDEF(&ent->data);
				}
				break;

			case ST_DATETIME: {
				char *tmp;

				tmp = emalloc(len + 1);
				memcpy(tmp, (char *)s, len);
				tmp[len] = '\0';

				Z_LVAL(ent->data) = php_parse_date(tmp, NULL);
				/* date out of range < 1969 or > 2038 */
				if (Z_LVAL(ent->data) == -1) {
					ZVAL_STRINGL(&ent->data, (char *)s, len);
				}
				efree(tmp);
			}
				break;

			default:
				break;
		}
	}


   Creates a new packet and serializes the given value */
PHP_FUNCTION(wddx_serialize_value)
{
	zval *var;
	char *comment = NULL;
	size_t comment_len = 0;
	wddx_packet *packet;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|s", &var, &comment, &comment_len) == FAILURE) {
		return;
	}

	packet = php_wddx_constructor();

	php_wddx_packet_start(packet, comment, comment_len);
	php_wddx_serialize_var(packet, var, NULL);
	php_wddx_packet_end(packet);
	smart_str_0(packet);

	RETVAL_STR_COPY(packet->s);
	php_wddx_destructor(packet);


 */
static int wddx_stack_init(wddx_stack *stack)
{
	stack->top = 0;
	stack->elements = (void **) safe_emalloc(sizeof(void **), STACK_BLOCK_SIZE, 0);
	stack->max = STACK_BLOCK_SIZE;
	stack->varname = NULL;
	stack->done = 0;

	return SUCCESS;


 */
int php_wddx_deserialize_ex(const char *value, size_t vallen, zval *return_value)
{
	wddx_stack stack;
	XML_Parser parser;
	st_entry *ent;
	int retval;

	wddx_stack_init(&stack);
	parser = XML_ParserCreate((XML_Char *) "UTF-8");

	XML_SetUserData(parser, &stack);
	XML_SetElementHandler(parser, php_wddx_push_element, php_wddx_pop_element);
	XML_SetCharacterDataHandler(parser, php_wddx_process_data);

	/* XXX value should be parsed in the loop to exhaust size_t */
	XML_Parse(parser, (const XML_Char *) value, (int)vallen, 1);

	XML_ParserFree(parser);

	if (stack.top == 1) {
		wddx_stack_top(&stack, (void**)&ent);
		ZVAL_COPY(return_value, &ent->data);
		retval = SUCCESS;
	} else {
		retval = FAILURE;
	}

	wddx_stack_destroy(&stack);

	return retval;


 */
PHP_MINIT_FUNCTION(wddx)
{
	le_wddx = zend_register_list_destructors_ex(release_wddx_packet_rsrc, NULL, "wddx", module_number);

#if HAVE_PHP_SESSION && !defined(COMPILE_DL_SESSION)
	php_session_register_serializer("wddx",
									PS_SERIALIZER_ENCODE_NAME(wddx),
									PS_SERIALIZER_DECODE_NAME(wddx));
#endif

	return SUCCESS;


 */
PS_SERIALIZER_DECODE_FUNC(wddx)
{
	zval retval;
	zval *ent;
	zend_string *key;
	zend_ulong idx;
	int ret;

	if (vallen == 0) {
		return SUCCESS;
	}

	ZVAL_UNDEF(&retval);
	if ((ret = php_wddx_deserialize_ex(val, vallen, &retval)) == SUCCESS) {
		if (Z_TYPE(retval) != IS_ARRAY) {
			zval_dtor(&retval);
			return FAILURE;
		}
		ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL(retval), idx, key, ent) {
			if (key == NULL) {
				key = zend_long_to_str(idx);
			} else {
				zend_string_addref(key);
			}
			if (php_set_session_var(key, ent, NULL)) {
				if (Z_REFCOUNTED_P(ent)) Z_ADDREF_P(ent);
			}
			PS_ADD_VAR(key);
			zend_string_release(key);
		} ZEND_HASH_FOREACH_END();
	}

	zval_ptr_dtor(&retval);

	return ret;


 */
static int wddx_stack_top(wddx_stack *stack, void **element)
{
	if (stack->top > 0) {
		*element = stack->elements[stack->top - 1];
		return SUCCESS;
	} else {
		*element = NULL;
		return FAILURE;
	}


 */
PS_SERIALIZER_ENCODE_FUNC(wddx)
{
	wddx_packet *packet;
	zend_string *str;
	PS_ENCODE_VARS;

	packet = php_wddx_constructor();

	php_wddx_packet_start(packet, NULL, 0);
	php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);

	PS_ENCODE_LOOP(
		php_wddx_serialize_var(packet, struc, key);
	);

	php_wddx_add_chunk_static(packet, WDDX_STRUCT_E);
	php_wddx_packet_end(packet);
	smart_str_0(packet);
	str = zend_string_copy(packet->s);
	php_wddx_destructor(packet);

	return str;


   Starts a WDDX packet with optional comment and returns the packet id */
PHP_FUNCTION(wddx_packet_start)
{
	char *comment = NULL;
	size_t comment_len = 0;
	wddx_packet *packet;

	comment = NULL;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &comment, &comment_len) == FAILURE) {
		return;
	}

	packet = php_wddx_constructor();

	php_wddx_packet_start(packet, comment, comment_len);
	php_wddx_add_chunk_static(packet, WDDX_STRUCT_S);

	RETURN_RES(zend_register_resource(packet, le_wddx));


   Deserializes given packet and returns a PHP value */
PHP_FUNCTION(wddx_deserialize)
{
	zval *packet;
	php_stream *stream = NULL;
	zend_string *payload = NULL;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &packet) == FAILURE) {
		return;
	}

	if (Z_TYPE_P(packet) == IS_STRING) {
		payload = Z_STR_P(packet);
	} else if (Z_TYPE_P(packet) == IS_RESOURCE) {
		php_stream_from_zval(stream, packet);
		if (stream) {
			payload = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0);
		}
	} else {
		php_error_docref(NULL, E_WARNING, "Expecting parameter 1 to be a string or a stream");
		return;
	}

	if (payload == NULL) {
		return;
	}

	php_wddx_deserialize_ex(ZSTR_VAL(payload), ZSTR_LEN(payload), return_value);

	if (stream) {
		efree(payload);
	}


 */
static void php_wddx_serialize_boolean(wddx_packet *packet, zval *var)
{
	php_wddx_add_chunk(packet, Z_TYPE_P(var) == IS_TRUE ? WDDX_BOOLEAN_TRUE : WDDX_BOOLEAN_FALSE);


   Serializes given variables and adds them to packet given by packet_id */
PHP_FUNCTION(wddx_add_vars)
{
	int num_args, i;
	zval *args = NULL;
	zval *packet_id;
	wddx_packet *packet = NULL;

	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r+", &packet_id, &args, &num_args) == FAILURE) {
		return;
	}

	if ((packet = (wddx_packet *)zend_fetch_resource(Z_RES_P(packet_id), "WDDX packet ID", le_wddx)) == NULL) {
		RETURN_FALSE;
	}

	for (i=0; i<num_args; i++) {
		zval *arg;
		if (!Z_ISREF(args[i])) {
			arg = &args[i];
		} else {
			arg = Z_REFVAL(args[i]);
		}
		if (Z_TYPE_P(arg) != IS_ARRAY && Z_TYPE_P(arg) != IS_OBJECT) {
			convert_to_string_ex(arg);
		}
		php_wddx_add_var(packet, arg);
	}

	RETURN_TRUE;


 */
static void php_wddx_serialize_string(wddx_packet *packet, zval *var)
{
	php_wddx_add_chunk_static(packet, WDDX_STRING_S);

	if (Z_STRLEN_P(var) > 0) {
		zend_string *buf = php_escape_html_entities(
			(unsigned char *) Z_STRVAL_P(var), Z_STRLEN_P(var), 0, ENT_QUOTES, NULL);

		php_wddx_add_chunk_ex(packet, ZSTR_VAL(buf), ZSTR_LEN(buf));

		zend_string_release(buf);
	}
	php_wddx_add_chunk_static(packet, WDDX_STRING_E);


 */
static void php_wddx_push_element(void *user_data, const XML_Char *name, const XML_Char **atts)
{
	st_entry ent;
	wddx_stack *stack = (wddx_stack *)user_data;
	if (!strcmp((char *)name, EL_PACKET)) {
		int i;

		if (atts) for (i=0; atts[i]; i++) {
			if (!strcmp((char *)atts[i], EL_VERSION)) {
				/* nothing for now */
			}
		}
	} else if (!strcmp((char *)name, EL_STRING)) {
		ent.type = ST_STRING;
		SET_STACK_VARNAME;

		ZVAL_STR(&ent.data, ZSTR_EMPTY_ALLOC());
		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	} else if (!strcmp((char *)name, EL_BINARY)) {
		ent.type = ST_BINARY;
		SET_STACK_VARNAME;

		ZVAL_STR(&ent.data, ZSTR_EMPTY_ALLOC());
		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	} else if (!strcmp((char *)name, EL_CHAR)) {
		int i;

		if (atts) for (i = 0; atts[i]; i++) {
			if (!strcmp((char *)atts[i], EL_CHAR_CODE) && atts[++i] && atts[i][0]) {
				char tmp_buf[2];

				snprintf(tmp_buf, sizeof(tmp_buf), "%c", (char)strtol((char *)atts[i], NULL, 16));
				php_wddx_process_data(user_data, (XML_Char *) tmp_buf, strlen(tmp_buf));
				break;
			}
		}
	} else if (!strcmp((char *)name, EL_NUMBER)) {
		ent.type = ST_NUMBER;
		SET_STACK_VARNAME;

		ZVAL_LONG(&ent.data, 0);
		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	} else if (!strcmp((char *)name, EL_BOOLEAN)) {
		int i;

		if (atts) for (i = 0; atts[i]; i++) {
			if (!strcmp((char *)atts[i], EL_VALUE) && atts[++i] && atts[i][0]) {
				ent.type = ST_BOOLEAN;
				SET_STACK_VARNAME;

				ZVAL_TRUE(&ent.data);
				wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
				php_wddx_process_data(user_data, atts[i], strlen((char *)atts[i]));
				break;
			}
		}
	} else if (!strcmp((char *)name, EL_NULL)) {
		ent.type = ST_NULL;
		SET_STACK_VARNAME;

		ZVAL_NULL(&ent.data);

		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	} else if (!strcmp((char *)name, EL_ARRAY)) {
		ent.type = ST_ARRAY;
		SET_STACK_VARNAME;

		array_init(&ent.data);
		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	} else if (!strcmp((char *)name, EL_STRUCT)) {
		ent.type = ST_STRUCT;
		SET_STACK_VARNAME;
		array_init(&ent.data);
		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	} else if (!strcmp((char *)name, EL_VAR)) {
		int i;

		if (atts) for (i = 0; atts[i]; i++) {
			if (!strcmp((char *)atts[i], EL_NAME) && atts[++i] && atts[i][0]) {
				if (stack->varname) efree(stack->varname);
				stack->varname = estrdup((char *)atts[i]);
				break;
			}
		}
	} else if (!strcmp((char *)name, EL_RECORDSET)) {
		int i;

		ent.type = ST_RECORDSET;
		SET_STACK_VARNAME;
		array_init(&ent.data);

		if (atts) for (i = 0; atts[i]; i++) {
			if (!strcmp((char *)atts[i], "fieldNames") && atts[++i] && atts[i][0]) {
				zval tmp;
				char *key;
				const char *p1, *p2, *endp;

				endp = (char *)atts[i] + strlen((char *)atts[i]);
				p1 = (char *)atts[i];
				while ((p2 = php_memnstr(p1, ",", sizeof(",")-1, endp)) != NULL) {
					key = estrndup(p1, p2 - p1);
					array_init(&tmp);
					add_assoc_zval_ex(&ent.data, key, p2 - p1, &tmp);
					p1 = p2 + sizeof(",")-1;
					efree(key);
				}

				if (p1 <= endp) {
					array_init(&tmp);
					add_assoc_zval_ex(&ent.data, p1, endp - p1, &tmp);
				}

				break;
			}
		}

		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	} else if (!strcmp((char *)name, EL_FIELD)) {
		int i;
		st_entry ent;

		ent.type = ST_FIELD;
		ent.varname = NULL;
		ZVAL_UNDEF(&ent.data);

		if (atts) for (i = 0; atts[i]; i++) {
			if (!strcmp((char *)atts[i], EL_NAME) && atts[++i] && atts[i][0]) {
				st_entry *recordset;
				zval *field;

				if (wddx_stack_top(stack, (void**)&recordset) == SUCCESS &&
					recordset->type == ST_RECORDSET &&
					(field = zend_hash_str_find(Z_ARRVAL(recordset->data), (char*)atts[i], strlen((char *)atts[i]))) != NULL) {
					ZVAL_COPY_VALUE(&ent.data, field);
				}

				break;
			}
		}

		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	} else if (!strcmp((char *)name, EL_DATETIME)) {
		ent.type = ST_DATETIME;
		SET_STACK_VARNAME;

		ZVAL_LONG(&ent.data, 0);
		wddx_stack_push((wddx_stack *)stack, &ent, sizeof(st_entry));
	}


 */
static int wddx_stack_destroy(wddx_stack *stack)
{
	register int i;

	if (stack->elements) {
		for (i = 0; i < stack->top; i++) {
			zval_ptr_dtor(&((st_entry *)stack->elements[i])->data);
			if (((st_entry *)stack->elements[i])->varname) {
				efree(((st_entry *)stack->elements[i])->varname);
			}
			efree(stack->elements[i]);
		}
		efree(stack->elements);
	}
	return SUCCESS;


 */
wddx_packet *php_wddx_constructor(void)
{
	smart_str *packet;

	packet = ecalloc(1, sizeof(smart_str));

	return packet;


SERVER-58203 factor out logging statements into helper functions

void DocumentSourceUnionWith::recordPlanSummaryStats(const Pipeline& pipeline) {
    for (auto&& source : pipeline.getSources()) {
        if (auto specificStats = source->getSpecificStats()) {
            specificStats->accumulate(_stats.planSummaryStats);
        }
    }
}


boost::intrusive_ptr<DocumentSource> DocumentSourceUnionWith::createFromBson(
    BSONElement elem, const boost::intrusive_ptr<ExpressionContext>& expCtx) {
    uassert(ErrorCodes::FailedToParse,
            str::stream()
                << "the $unionWith stage specification must be an object or string, but found "
                << typeName(elem.type()),
            elem.type() == BSONType::Object || elem.type() == BSONType::String);

    NamespaceString unionNss;
    std::vector<BSONObj> pipeline;
    if (elem.type() == BSONType::String) {
        unionNss = NamespaceString(expCtx->ns.db().toString(), elem.valueStringData());
    } else {
        auto unionWithSpec =
            UnionWithSpec::parse(IDLParserErrorContext(kStageName), elem.embeddedObject());
        if (unionWithSpec.getColl()) {
            unionNss = NamespaceString(expCtx->ns.db().toString(), *unionWithSpec.getColl());
        } else {
            // if no collection specified, it must have $documents as first field in pipeline
            validateUnionWithCollectionlessPipeline(unionWithSpec.getPipeline());
            unionNss = NamespaceString::makeCollectionlessAggregateNSS(expCtx->ns.db());
        }
        pipeline = unionWithSpec.getPipeline().value_or(std::vector<BSONObj>{});
    }
    return make_intrusive<DocumentSourceUnionWith>(
        expCtx,
        buildPipelineFromViewDefinition(
            expCtx, expCtx->getResolvedNamespace(std::move(unionNss)), std::move(pipeline)));
}


DocumentSource::GetNextResult DocumentSourceUnionWith::doGetNext() {
    if (!_pipeline) {
        // We must have already been disposed, so we're finished.
        return GetNextResult::makeEOF();
    }

    if (_executionState == ExecutionProgress::kIteratingSource) {
        auto nextInput = pSource->getNext();
        if (!nextInput.isEOF()) {
            return nextInput;
        }
        _executionState = ExecutionProgress::kStartingSubPipeline;
        // All documents from the base collection have been returned, switch to iterating the sub-
        // pipeline by falling through below.
    }

    if (_executionState == ExecutionProgress::kStartingSubPipeline) {
        auto serializedPipe = _pipeline->serializeToBson();
        // $$SEARCH_META can be set during runtime earlier in the pipeline, and therefore must be
        // copied to the subpipeline manually.
        if (pExpCtx->variables.hasConstantValue(Variables::kSearchMetaId)) {
            _pipeline->getContext()->variables.setReservedValue(
                Variables::kSearchMetaId,
                pExpCtx->variables.getValue(Variables::kSearchMetaId, Document()),
                true);
        }
        logStartingSubPipeline(serializedPipe);
        try {
            _pipeline =
                pExpCtx->mongoProcessInterface->attachCursorSourceToPipeline(_pipeline.release());
            _executionState = ExecutionProgress::kIteratingSubPipeline;
        } catch (const ExceptionFor<ErrorCodes::CommandOnShardedViewNotSupportedOnMongod>& e) {
            _pipeline = buildPipelineFromViewDefinition(
                pExpCtx,
                ExpressionContext::ResolvedNamespace{e->getNamespace(), e->getPipeline()},
                serializedPipe);
            logShardedViewFound(e);
            return doGetNext();
        }
    }

    auto res = _pipeline->getNext();
    if (res)
        return std::move(*res);

    // Record the plan summary stats after $unionWith operation is done.
    recordPlanSummaryStats(*_pipeline);

    _executionState = ExecutionProgress::kFinished;
    return GetNextResult::makeEOF();
}


void validateUnionWithCollectionlessPipeline(
    const boost::optional<std::vector<mongo::BSONObj>>& pipeline) {
    uassert(ErrorCodes::FailedToParse,
            "$unionWith stage without explicit collection must have a pipeline with $documents as "
            "first stage",
            pipeline && pipeline->size() > 0 &&
                !(*pipeline)[0].getField(DocumentSourceDocuments::kStageName).eoo());
}


void DocumentSourceUnionWith::doDispose() {
    if (_pipeline) {
        _stats.planSummaryStats.usedDisk =
            _stats.planSummaryStats.usedDisk || _pipeline->usedDisk();
        recordPlanSummaryStats(*_pipeline);

        if (!_pipeline->getContext()->explain) {
            _pipeline->dispose(pExpCtx->opCtx);
            _pipeline.reset();
        }
    }
}


bool DocumentSourceUnionWith::usedDisk() {
    if (_pipeline) {
        _stats.planSummaryStats.usedDisk =
            _stats.planSummaryStats.usedDisk || _pipeline->usedDisk();
    }
    return _stats.planSummaryStats.usedDisk;
}


DepsTracker::State DocumentSourceUnionWith::getDependencies(DepsTracker* deps) const {
    // Since the $unionWith stage is a simple passthrough, we *could* report SEE_NEXT here in an
    // attempt to get a covered plan for the base collection. The ideal solution would involve
    // pushing down any dependencies to the inner pipeline as well.
    return DepsTracker::State::NOT_SUPPORTED;
}


std::unique_ptr<DocumentSourceUnionWith::LiteParsed> DocumentSourceUnionWith::LiteParsed::parse(
    const NamespaceString& nss, const BSONElement& spec) {
    uassert(ErrorCodes::FailedToParse,
            str::stream()
                << "the $unionWith stage specification must be an object or string, but found "
                << typeName(spec.type()),
            spec.type() == BSONType::Object || spec.type() == BSONType::String);

    NamespaceString unionNss;
    boost::optional<LiteParsedPipeline> liteParsedPipeline;
    if (spec.type() == BSONType::String) {
        unionNss = NamespaceString(nss.db(), spec.valueStringData());
    } else {
        auto unionWithSpec =
            UnionWithSpec::parse(IDLParserErrorContext(kStageName), spec.embeddedObject());
        if (unionWithSpec.getColl()) {
            unionNss = NamespaceString(nss.db(), *unionWithSpec.getColl());
        } else {
            // If no collection specified, it must have $documents as first field in pipeline.
            validateUnionWithCollectionlessPipeline(unionWithSpec.getPipeline());
            unionNss = NamespaceString::makeCollectionlessAggregateNSS(nss.db());
        }

        // Recursively lite parse the nested pipeline, if one exists.
        if (unionWithSpec.getPipeline()) {
            liteParsedPipeline = LiteParsedPipeline(unionNss, *unionWithSpec.getPipeline());
        }
    }

    return std::make_unique<DocumentSourceUnionWith::LiteParsed>(
        spec.fieldName(), std::move(unionNss), std::move(liteParsedPipeline));
}


Value DocumentSourceUnionWith::serialize(boost::optional<ExplainOptions::Verbosity> explain) const {
    auto collectionless = _pipeline->getContext()->ns.isCollectionlessAggregateNS();
    if (explain) {
        // There are several different possible states depending on the explain verbosity as well as
        // the other stages in the pipeline:
        //  * If verbosity is queryPlanner, then the sub-pipeline should be untouched and we can
        //  explain it directly.
        //  * If verbosity is execStats or allPlansExecution, then whether or not to explain the
        //  sub-pipeline depends on if we've started reading from it. For instance, there could be a
        //  $limit stage after the $unionWith which results in only reading from the base collection
        //  branch and not the sub-pipeline.
        Pipeline* pipeCopy = nullptr;
        if (*explain == ExplainOptions::Verbosity::kQueryPlanner) {
            pipeCopy = Pipeline::create(_pipeline->getSources(), _pipeline->getContext()).release();
        } else if (*explain >= ExplainOptions::Verbosity::kExecStats &&
                   _executionState > ExecutionProgress::kIteratingSource) {
            // We've either exhausted the sub-pipeline or at least started iterating it. Use the
            // cached pipeline to get the explain output since the '_pipeline' may have been
            // modified for any optimizations or pushdowns into the initial $cursor stage.
            pipeCopy = Pipeline::create(_cachedPipeline, _pipeline->getContext()).release();
        } else {
            // The plan does not require reading from the sub-pipeline, so just include the
            // serialization in the explain output.
            BSONArrayBuilder bab;
            for (auto&& stage : _pipeline->serialize())
                bab << stage;
            auto spec = collectionless
                ? DOC("pipeline" << bab.arr())
                : DOC("coll" << _pipeline->getContext()->ns.coll() << "pipeline" << bab.arr());
            return Value(DOC(getSourceName() << spec));
        }

        invariant(pipeCopy);
        BSONObj explainLocal =
            pExpCtx->mongoProcessInterface->preparePipelineAndExplain(pipeCopy, *explain);
        LOGV2_DEBUG(4553501, 3, "$unionWith attached cursor to pipeline for explain");
        // We expect this to be an explanation of a pipeline -- there should only be one field.
        invariant(explainLocal.nFields() == 1);

        auto spec = collectionless ? DOC("pipeline" << explainLocal.firstElement())
                                   : DOC("coll" << _pipeline->getContext()->ns.coll() << "pipeline"
                                                << explainLocal.firstElement());
        return Value(DOC(getSourceName() << spec));
    } else {
        BSONArrayBuilder bab;
        for (auto&& stage : _pipeline->serialize())
            bab << stage;
        auto spec = collectionless
            ? DOC("pipeline" << bab.arr())
            : DOC("coll" << _pipeline->getContext()->ns.coll() << "pipeline" << bab.arr());
        return Value(DOC(getSourceName() << spec));
    }
}


void DocumentSourceUnionWith::detachFromOperationContext() {
    // We have a pipeline we're going to be executing across multiple calls to getNext(), so we
    // use Pipeline::detachFromOperationContext() to take care of updating the Pipeline's
    // ExpressionContext.
    if (_pipeline) {
        _pipeline->detachFromOperationContext();
    }
}


void DocumentSourceUnionWith::addInvolvedCollections(
    stdx::unordered_set<NamespaceString>* collectionNames) const {
    collectionNames->insert(_pipeline->getContext()->ns);
    collectionNames->merge(_pipeline->getInvolvedCollections());
}


MONGO_COMPILER_NOINLINE void DocumentSourceUnionWith::logShardedViewFound(
    const ExceptionFor<ErrorCodes::CommandOnShardedViewNotSupportedOnMongod>& e) {
    LOGV2_DEBUG(4556300,
                3,
                "$unionWith found view definition. ns: {ns}, pipeline: {pipeline}. New "
                "$unionWith sub-pipeline: {new_pipe}",
                "ns"_attr = e->getNamespace(),
                "pipeline"_attr = Value(e->getPipeline()),
                "new_pipe"_attr = _pipeline->serializeToBson());
}


PrivilegeVector DocumentSourceUnionWith::LiteParsed::requiredPrivileges(
    bool isMongos, bool bypassDocumentValidation) const {
    PrivilegeVector requiredPrivileges;
    invariant(_pipelines.size() <= 1);
    invariant(_foreignNss);

    // If no pipeline is specified, then assume that we're reading directly from the collection.
    // Otherwise check whether the pipeline starts with an "initial source" indicating that we don't
    // require the "find" privilege.
    if (_pipelines.empty() || !_pipelines[0].startsWithInitialSource()) {
        Privilege::addPrivilegeToPrivilegeVector(
            &requiredPrivileges,
            Privilege(ResourcePattern::forExactNamespace(*_foreignNss), ActionType::find));
    }

    // Add the sub-pipeline privileges, if one was specified.
    if (!_pipelines.empty()) {
        const LiteParsedPipeline& pipeline = _pipelines[0];
        Privilege::addPrivilegesToPrivilegeVector(
            &requiredPrivileges,
            std::move(pipeline.requiredPrivileges(isMongos, bypassDocumentValidation)));
    }
    return requiredPrivileges;
}


void DocumentSourceUnionWith::reattachToOperationContext(OperationContext* opCtx) {
    // We have a pipeline we're going to be executing across multiple calls to getNext(), so we
    // use Pipeline::reattachToOperationContext() to take care of updating the Pipeline's
    // ExpressionContext.
    if (_pipeline) {
        _pipeline->reattachToOperationContext(opCtx);
    }
}


std::unique_ptr<Pipeline, PipelineDeleter> buildPipelineFromViewDefinition(
    const boost::intrusive_ptr<ExpressionContext>& expCtx,
    ExpressionContext::ResolvedNamespace resolvedNs,
    std::vector<BSONObj> currentPipeline) {

    auto validatorCallback = [](const Pipeline& pipeline) {
        const auto& sources = pipeline.getSources();
        std::for_each(sources.begin(), sources.end(), [](auto& src) {
            uassert(31441,
                    str::stream() << src->getSourceName()
                                  << " is not allowed within a $unionWith's sub-pipeline",
                    src->constraints().isAllowedInUnionPipeline());
        });
    };

    // Copy the ExpressionContext of the base aggregation, using the inner namespace instead.
    auto unionExpCtx = expCtx->copyForSubPipeline(resolvedNs.ns);

    if (resolvedNs.pipeline.empty()) {
        return Pipeline::parse(currentPipeline, unionExpCtx, validatorCallback);
    }
    auto resolvedPipeline = std::move(resolvedNs.pipeline);
    resolvedPipeline.reserve(currentPipeline.size() + resolvedPipeline.size());
    resolvedPipeline.insert(resolvedPipeline.end(),
                            std::make_move_iterator(currentPipeline.begin()),
                            std::make_move_iterator(currentPipeline.end()));

    MakePipelineOptions opts;
    opts.attachCursorSource = false;
    opts.validator = validatorCallback;
    return Pipeline::makePipeline(std::move(resolvedPipeline), unionExpCtx, opts);
}


Pipeline::SourceContainer::iterator DocumentSourceUnionWith::doOptimizeAt(
    Pipeline::SourceContainer::iterator itr, Pipeline::SourceContainer* container) {
    auto duplicateAcrossUnion = [&](auto&& nextStage) {
        _pipeline->addFinalSource(nextStage->clone());
        auto newStageItr = container->insert(itr, std::move(nextStage));
        container->erase(std::next(itr));
        return newStageItr == container->begin() ? newStageItr : std::prev(newStageItr);
    };
    if (std::next(itr) != container->end()) {
        if (auto nextMatch = dynamic_cast<DocumentSourceMatch*>((*std::next(itr)).get()))
            return duplicateAcrossUnion(nextMatch);
        else if (auto nextProject = dynamic_cast<DocumentSourceSingleDocumentTransformation*>(
                     (*std::next(itr)).get()))
            return duplicateAcrossUnion(nextProject);
    }
    return std::next(itr);
};


MONGO_COMPILER_NOINLINE void DocumentSourceUnionWith::logStartingSubPipeline(
    const std::vector<BSONObj>& serializedPipe) {
    LOGV2_DEBUG(23869,
                1,
                "$unionWith attaching cursor to pipeline {pipeline}",
                "pipeline"_attr = serializedPipe);
}


DocumentSourceUnionWith::~DocumentSourceUnionWith() {
    if (_pipeline && _pipeline->getContext()->explain) {
        _pipeline->dispose(pExpCtx->opCtx);
        _pipeline.reset();
    }
}


Replace a run-time assertion failure with a warning message when parsing corrupt DWARF data.

	PR 29289
	* dwarf.c (display_debug_names): Replace assert with a warning
	message.

range_entry_compar (const void *ap, const void *bp)
{
  const struct range_entry *a_re = (const struct range_entry *) ap;
  const struct range_entry *b_re = (const struct range_entry *) bp;
  const dwarf_vma a = a_re->ranges_offset;
  const dwarf_vma b = b_re->ranges_offset;

  return (a > b) - (b > a);
}


init_dwarf_regnames_by_elf_machine_code (unsigned int e_machine)
{
  dwarf_regnames_lookup_func = NULL;

  switch (e_machine)
    {
    case EM_386:
      init_dwarf_regnames_i386 ();
      break;

    case EM_IAMCU:
      init_dwarf_regnames_iamcu ();
      break;

    case EM_X86_64:
    case EM_L1OM:
    case EM_K1OM:
      init_dwarf_regnames_x86_64 ();
      break;

    case EM_AARCH64:
      init_dwarf_regnames_aarch64 ();
      break;

    case EM_S390:
      init_dwarf_regnames_s390 ();
      break;

    case EM_RISCV:
      init_dwarf_regnames_riscv ();
      break;

    default:
      break;
    }
}


regname_internal_by_table_only (unsigned int regno)
{
  if (dwarf_regnames != NULL
      && regno < dwarf_regnames_count
      && dwarf_regnames [regno] != NULL)
    return dwarf_regnames [regno];

  return NULL;
}


dwarf_vmatoa_1 (const char *fmtch, dwarf_vma value, unsigned num_bytes)
{
  /* As dwarf_vmatoa is used more then once in a printf call
     for output, we are cycling through a fixed array of pointers
     for return address.  */
  static int buf_pos = 0;
  static struct dwarf_vmatoa_buf
  {
    char place[64];
  } buf[16];
  char *ret;

  ret = buf[buf_pos++].place;
  buf_pos %= ARRAY_SIZE (buf);

  if (num_bytes)
    {
      /* Printf does not have a way of specifying a maximum field width for an
	 integer value, so we print the full value into a buffer and then select
	 the precision we need.  */
      snprintf (ret, sizeof (buf[0].place), DWARF_VMA_FMT_LONG, value);
      if (num_bytes > 8)
	num_bytes = 8;
      return ret + (16 - 2 * num_bytes);
    }
  else
    {
      char fmt[32];

      if (fmtch)
	sprintf (fmt, "%%%s%s", DWARF_VMA_FMT, fmtch);
      else
	sprintf (fmt, "%%%s", DWARF_VMA_FMT);
      snprintf (ret, sizeof (buf[0].place), fmt, value);
      return ret;
    }
}


fetch_indirect_string (dwarf_vma offset)
{
  struct dwarf_section *section = &debug_displays [str].section;
  const unsigned char * ret;

  if (section->start == NULL)
    return (const unsigned char *) _("<no .debug_str section>");

  if (offset >= section->size)
    {
      warn (_("DW_FORM_strp offset too big: 0x%s\n"),
	    dwarf_vmatoa ("x", offset));
      return (const unsigned char *) _("<offset is too big>");
    }

  ret = section->start + offset;
  /* Unfortunately we cannot rely upon the .debug_str section ending with a
     NUL byte.  Since our caller is expecting to receive a well formed C
     string we test for the lack of a terminating byte here.  */
  if (strnlen ((const char *) ret, section->size - offset)
      == section->size - offset)
    ret = (const unsigned char *)
      _("<no NUL byte at end of .debug_str section>");

  return ret;
}


get_line_filename_and_dirname (dwarf_vma line_offset,
			       dwarf_vma fileidx,
			       unsigned char **dir_name)
{
  struct dwarf_section *section = &debug_displays [line].section;
  unsigned char *hdrptr, *dirtable, *file_name;
  unsigned int offset_size;
  unsigned int version, opcode_base;
  dwarf_vma length, diridx;
  const unsigned char * end;

  *dir_name = NULL;
  if (section->start == NULL
      || line_offset >= section->size
      || fileidx == 0)
    return NULL;

  hdrptr = section->start + line_offset;
  end = section->start + section->size;

  SAFE_BYTE_GET_AND_INC (length, hdrptr, 4, end);
  if (length == 0xffffffff)
    {
      /* This section is 64-bit DWARF 3.  */
      SAFE_BYTE_GET_AND_INC (length, hdrptr, 8, end);
      offset_size = 8;
    }
  else
    offset_size = 4;

  if (length > (size_t) (end - hdrptr)
      || length < 2 + offset_size + 1 + 3 + 1)
    return NULL;
  end = hdrptr + length;

  SAFE_BYTE_GET_AND_INC (version, hdrptr, 2, end);
  if (version != 2 && version != 3 && version != 4)
    return NULL;
  hdrptr += offset_size + 1;/* Skip prologue_length and min_insn_length.  */
  if (version >= 4)
    hdrptr++;		    /* Skip max_ops_per_insn.  */
  hdrptr += 3;		    /* Skip default_is_stmt, line_base, line_range.  */

  SAFE_BYTE_GET_AND_INC (opcode_base, hdrptr, 1, end);
  if (opcode_base == 0
      || opcode_base - 1 >= (size_t) (end - hdrptr))
    return NULL;

  hdrptr += opcode_base - 1;

  dirtable = hdrptr;
  /* Skip over dirname table.  */
  while (*hdrptr != '\0')
    {
      hdrptr += strnlen ((char *) hdrptr, end - hdrptr);
      if (hdrptr < end)
	hdrptr++;
      if (hdrptr >= end)
	return NULL;
    }
  hdrptr++;		    /* Skip the NUL at the end of the table.  */

  /* Now skip over preceding filename table entries.  */
  for (; hdrptr < end && *hdrptr != '\0' && fileidx > 1; fileidx--)
    {
      hdrptr += strnlen ((char *) hdrptr, end - hdrptr);
      if (hdrptr < end)
	hdrptr++;
      SKIP_ULEB (hdrptr, end);
      SKIP_ULEB (hdrptr, end);
      SKIP_ULEB (hdrptr, end);
    }
  if (hdrptr >= end || *hdrptr == '\0')
    return NULL;

  file_name = hdrptr;
  hdrptr += strnlen ((char *) hdrptr, end - hdrptr);
  if (hdrptr < end)
    hdrptr++;
  if (hdrptr >= end)
    return NULL;
  READ_ULEB (diridx, hdrptr, end);
  if (diridx == 0)
    return file_name;
  for (; dirtable < end && *dirtable != '\0' && diridx > 1; diridx--)
    {
      dirtable += strnlen ((char *) dirtable, end - dirtable);
      if (dirtable < end)
	dirtable++;
    }
  if (dirtable >= end || *dirtable == '\0')
    return NULL;
  *dir_name = dirtable;
  return file_name;
}


fetch_alt_indirect_string (dwarf_vma offset)
{
  separate_info * i;

  if (! do_follow_links)
    return "";

  if (first_separate_info == NULL)
    return _("<no links available>");

  for (i = first_separate_info; i != NULL; i = i->next)
    {
      struct dwarf_section * section;
      const char *           ret;

      if (! load_debug_section (separate_debug_str, i->handle))
	continue;

      section = &debug_displays [separate_debug_str].section;

      if (section->start == NULL)
	continue;

      if (offset >= section->size)
	continue;

      ret = (const char *) (section->start + offset);
      /* Unfortunately we cannot rely upon the .debug_str section ending with a
	 NUL byte.  Since our caller is expecting to receive a well formed C
	 string we test for the lack of a terminating byte here.  */
      if (strnlen ((const char *) ret, section->size - offset)
	  == section->size - offset)
	return _("<no NUL byte at end of alt .debug_str section>");

      return ret;
    }

  warn (_("DW_FORM_GNU_strp_alt offset (%s) too big or no string sections available\n"),
	dwarf_vmatoa ("x", offset));
  return _("<offset is too big>");
}


xcrealloc (void *ptr, size_t nmemb, size_t size)
{
  /* Check for overflow.  */
  if (nmemb >= ~(size_t) 0 / size)
    {
      error (_("Attempt to re-allocate an array with an excessive number of elements: 0x%lx\n"),
	     (long) nmemb);
      xexit (1);
    }

  return xrealloc (ptr, nmemb * size);
}


get_DW_SECT_short_name (unsigned int dw_sect)
{
  static char buf[16];

  switch (dw_sect)
    {
      case DW_SECT_INFO:
	return "info";
      case DW_SECT_TYPES:
	return "types";
      case DW_SECT_ABBREV:
	return "abbrev";
      case DW_SECT_LINE:
	return "line";
      case DW_SECT_LOC:
	return "loc";
      case DW_SECT_STR_OFFSETS:
	return "str_off";
      case DW_SECT_MACINFO:
	return "macinfo";
      case DW_SECT_MACRO:
	return "macro";
      default:
	break;
    }

  snprintf (buf, sizeof (buf), "%d", dw_sect);
  return buf;
}


load_cu_tu_indexes (void *file)
{
  /* If we have already loaded (or tried to load) the CU and TU indexes
     then do not bother to repeat the task.  */
  if (cu_tu_indexes_read == -1)
    {
      cu_tu_indexes_read = true;

      if (load_debug_section_with_follow (dwp_cu_index, file))
	if (! process_cu_tu_index (&debug_displays [dwp_cu_index].section, 0))
	  cu_tu_indexes_read = false;

      if (load_debug_section_with_follow (dwp_tu_index, file))
	if (! process_cu_tu_index (&debug_displays [dwp_tu_index].section, 0))
	  cu_tu_indexes_read = false;
    }

  return (bool) cu_tu_indexes_read;
}


decode_location_expression (unsigned char * data,
			    unsigned int pointer_size,
			    unsigned int offset_size,
			    int dwarf_version,
			    dwarf_vma length,
			    dwarf_vma cu_offset,
			    struct dwarf_section * section)
{
  unsigned op;
  dwarf_vma uvalue;
  dwarf_signed_vma svalue;
  unsigned char *end = data + length;
  int need_frame_base = 0;

  while (data < end)
    {
      op = *data++;

      switch (op)
	{
	case DW_OP_addr:
	  SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
	  printf ("DW_OP_addr: %s", dwarf_vmatoa ("x", uvalue));
	  break;
	case DW_OP_deref:
	  printf ("DW_OP_deref");
	  break;
	case DW_OP_const1u:
	  SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
	  printf ("DW_OP_const1u: %lu", (unsigned long) uvalue);
	  break;
	case DW_OP_const1s:
	  SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 1, end);
	  printf ("DW_OP_const1s: %ld", (long) svalue);
	  break;
	case DW_OP_const2u:
	  SAFE_BYTE_GET_AND_INC (uvalue, data, 2, end);
	  printf ("DW_OP_const2u: %lu", (unsigned long) uvalue);
	  break;
	case DW_OP_const2s:
	  SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 2, end);
	  printf ("DW_OP_const2s: %ld", (long) svalue);
	  break;
	case DW_OP_const4u:
	  SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end);
	  printf ("DW_OP_const4u: %lu", (unsigned long) uvalue);
	  break;
	case DW_OP_const4s:
	  SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 4, end);
	  printf ("DW_OP_const4s: %ld", (long) svalue);
	  break;
	case DW_OP_const8u:
	  SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end);
	  printf ("DW_OP_const8u: %lu ", (unsigned long) uvalue);
	  SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end);
	  printf ("%lu", (unsigned long) uvalue);
	  break;
	case DW_OP_const8s:
	  SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 4, end);
	  printf ("DW_OP_const8s: %ld ", (long) svalue);
	  SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 4, end);
	  printf ("%ld", (long) svalue);
	  break;
	case DW_OP_constu:
	  READ_ULEB (uvalue, data, end);
	  printf ("DW_OP_constu: %s", dwarf_vmatoa ("u", uvalue));
	  break;
	case DW_OP_consts:
	  READ_SLEB (svalue, data, end);
	  printf ("DW_OP_consts: %s", dwarf_vmatoa ("d", svalue));
	  break;
	case DW_OP_dup:
	  printf ("DW_OP_dup");
	  break;
	case DW_OP_drop:
	  printf ("DW_OP_drop");
	  break;
	case DW_OP_over:
	  printf ("DW_OP_over");
	  break;
	case DW_OP_pick:
	  SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
	  printf ("DW_OP_pick: %ld", (unsigned long) uvalue);
	  break;
	case DW_OP_swap:
	  printf ("DW_OP_swap");
	  break;
	case DW_OP_rot:
	  printf ("DW_OP_rot");
	  break;
	case DW_OP_xderef:
	  printf ("DW_OP_xderef");
	  break;
	case DW_OP_abs:
	  printf ("DW_OP_abs");
	  break;
	case DW_OP_and:
	  printf ("DW_OP_and");
	  break;
	case DW_OP_div:
	  printf ("DW_OP_div");
	  break;
	case DW_OP_minus:
	  printf ("DW_OP_minus");
	  break;
	case DW_OP_mod:
	  printf ("DW_OP_mod");
	  break;
	case DW_OP_mul:
	  printf ("DW_OP_mul");
	  break;
	case DW_OP_neg:
	  printf ("DW_OP_neg");
	  break;
	case DW_OP_not:
	  printf ("DW_OP_not");
	  break;
	case DW_OP_or:
	  printf ("DW_OP_or");
	  break;
	case DW_OP_plus:
	  printf ("DW_OP_plus");
	  break;
	case DW_OP_plus_uconst:
	  READ_ULEB (uvalue, data, end);
	  printf ("DW_OP_plus_uconst: %s", dwarf_vmatoa ("u", uvalue));
	  break;
	case DW_OP_shl:
	  printf ("DW_OP_shl");
	  break;
	case DW_OP_shr:
	  printf ("DW_OP_shr");
	  break;
	case DW_OP_shra:
	  printf ("DW_OP_shra");
	  break;
	case DW_OP_xor:
	  printf ("DW_OP_xor");
	  break;
	case DW_OP_bra:
	  SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 2, end);
	  printf ("DW_OP_bra: %ld", (long) svalue);
	  break;
	case DW_OP_eq:
	  printf ("DW_OP_eq");
	  break;
	case DW_OP_ge:
	  printf ("DW_OP_ge");
	  break;
	case DW_OP_gt:
	  printf ("DW_OP_gt");
	  break;
	case DW_OP_le:
	  printf ("DW_OP_le");
	  break;
	case DW_OP_lt:
	  printf ("DW_OP_lt");
	  break;
	case DW_OP_ne:
	  printf ("DW_OP_ne");
	  break;
	case DW_OP_skip:
	  SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 2, end);
	  printf ("DW_OP_skip: %ld", (long) svalue);
	  break;

	case DW_OP_lit0:
	case DW_OP_lit1:
	case DW_OP_lit2:
	case DW_OP_lit3:
	case DW_OP_lit4:
	case DW_OP_lit5:
	case DW_OP_lit6:
	case DW_OP_lit7:
	case DW_OP_lit8:
	case DW_OP_lit9:
	case DW_OP_lit10:
	case DW_OP_lit11:
	case DW_OP_lit12:
	case DW_OP_lit13:
	case DW_OP_lit14:
	case DW_OP_lit15:
	case DW_OP_lit16:
	case DW_OP_lit17:
	case DW_OP_lit18:
	case DW_OP_lit19:
	case DW_OP_lit20:
	case DW_OP_lit21:
	case DW_OP_lit22:
	case DW_OP_lit23:
	case DW_OP_lit24:
	case DW_OP_lit25:
	case DW_OP_lit26:
	case DW_OP_lit27:
	case DW_OP_lit28:
	case DW_OP_lit29:
	case DW_OP_lit30:
	case DW_OP_lit31:
	  printf ("DW_OP_lit%d", op - DW_OP_lit0);
	  break;

	case DW_OP_reg0:
	case DW_OP_reg1:
	case DW_OP_reg2:
	case DW_OP_reg3:
	case DW_OP_reg4:
	case DW_OP_reg5:
	case DW_OP_reg6:
	case DW_OP_reg7:
	case DW_OP_reg8:
	case DW_OP_reg9:
	case DW_OP_reg10:
	case DW_OP_reg11:
	case DW_OP_reg12:
	case DW_OP_reg13:
	case DW_OP_reg14:
	case DW_OP_reg15:
	case DW_OP_reg16:
	case DW_OP_reg17:
	case DW_OP_reg18:
	case DW_OP_reg19:
	case DW_OP_reg20:
	case DW_OP_reg21:
	case DW_OP_reg22:
	case DW_OP_reg23:
	case DW_OP_reg24:
	case DW_OP_reg25:
	case DW_OP_reg26:
	case DW_OP_reg27:
	case DW_OP_reg28:
	case DW_OP_reg29:
	case DW_OP_reg30:
	case DW_OP_reg31:
	  printf ("DW_OP_reg%d (%s)", op - DW_OP_reg0,
		  regname (op - DW_OP_reg0, 1));
	  break;

	case DW_OP_breg0:
	case DW_OP_breg1:
	case DW_OP_breg2:
	case DW_OP_breg3:
	case DW_OP_breg4:
	case DW_OP_breg5:
	case DW_OP_breg6:
	case DW_OP_breg7:
	case DW_OP_breg8:
	case DW_OP_breg9:
	case DW_OP_breg10:
	case DW_OP_breg11:
	case DW_OP_breg12:
	case DW_OP_breg13:
	case DW_OP_breg14:
	case DW_OP_breg15:
	case DW_OP_breg16:
	case DW_OP_breg17:
	case DW_OP_breg18:
	case DW_OP_breg19:
	case DW_OP_breg20:
	case DW_OP_breg21:
	case DW_OP_breg22:
	case DW_OP_breg23:
	case DW_OP_breg24:
	case DW_OP_breg25:
	case DW_OP_breg26:
	case DW_OP_breg27:
	case DW_OP_breg28:
	case DW_OP_breg29:
	case DW_OP_breg30:
	case DW_OP_breg31:
	  READ_SLEB (svalue, data, end);
	  printf ("DW_OP_breg%d (%s): %s", op - DW_OP_breg0,
		  regname (op - DW_OP_breg0, 1), dwarf_vmatoa ("d", svalue));
	  break;

	case DW_OP_regx:
	  READ_ULEB (uvalue, data, end);
	  printf ("DW_OP_regx: %s (%s)",
		  dwarf_vmatoa ("u", uvalue), regname (uvalue, 1));
	  break;
	case DW_OP_fbreg:
	  need_frame_base = 1;
	  READ_SLEB (svalue, data, end);
	  printf ("DW_OP_fbreg: %s", dwarf_vmatoa ("d", svalue));
	  break;
	case DW_OP_bregx:
	  READ_ULEB (uvalue, data, end);
	  READ_SLEB (svalue, data, end);
	  printf ("DW_OP_bregx: %s (%s) %s",
		  dwarf_vmatoa ("u", uvalue), regname (uvalue, 1),
		  dwarf_vmatoa ("d", svalue));
	  break;
	case DW_OP_piece:
	  READ_ULEB (uvalue, data, end);
	  printf ("DW_OP_piece: %s", dwarf_vmatoa ("u", uvalue));
	  break;
	case DW_OP_deref_size:
	  SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
	  printf ("DW_OP_deref_size: %ld", (long) uvalue);
	  break;
	case DW_OP_xderef_size:
	  SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
	  printf ("DW_OP_xderef_size: %ld", (long) uvalue);
	  break;
	case DW_OP_nop:
	  printf ("DW_OP_nop");
	  break;

	  /* DWARF 3 extensions.  */
	case DW_OP_push_object_address:
	  printf ("DW_OP_push_object_address");
	  break;
	case DW_OP_call2:
	  /* FIXME: Strictly speaking for 64-bit DWARF3 files
	     this ought to be an 8-byte wide computation.  */
	  SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 2, end);
	  printf ("DW_OP_call2: <0x%s>",
		  dwarf_vmatoa ("x", svalue + cu_offset));
	  break;
	case DW_OP_call4:
	  /* FIXME: Strictly speaking for 64-bit DWARF3 files
	     this ought to be an 8-byte wide computation.  */
	  SAFE_SIGNED_BYTE_GET_AND_INC (svalue, data, 4, end);
	  printf ("DW_OP_call4: <0x%s>",
		  dwarf_vmatoa ("x", svalue + cu_offset));
	  break;
	case DW_OP_call_ref:
	  /* FIXME: Strictly speaking for 64-bit DWARF3 files
	     this ought to be an 8-byte wide computation.  */
	  if (dwarf_version == -1)
	    {
	      printf (_("(DW_OP_call_ref in frame info)"));
	      /* No way to tell where the next op is, so just bail.  */
	      return need_frame_base;
	    }
	  if (dwarf_version == 2)
	    {
	      SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
	    }
	  else
	    {
	      SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
	    }
	  printf ("DW_OP_call_ref: <0x%s>", dwarf_vmatoa ("x", uvalue));
	  break;
	case DW_OP_form_tls_address:
	  printf ("DW_OP_form_tls_address");
	  break;
	case DW_OP_call_frame_cfa:
	  printf ("DW_OP_call_frame_cfa");
	  break;
	case DW_OP_bit_piece:
	  printf ("DW_OP_bit_piece: ");
	  READ_ULEB (uvalue, data, end);
	  printf (_("size: %s "), dwarf_vmatoa ("u", uvalue));
	  READ_ULEB (uvalue, data, end);
	  printf (_("offset: %s "), dwarf_vmatoa ("u", uvalue));
	  break;

	  /* DWARF 4 extensions.  */
	case DW_OP_stack_value:
	  printf ("DW_OP_stack_value");
	  break;

	case DW_OP_implicit_value:
	  printf ("DW_OP_implicit_value");
	  READ_ULEB (uvalue, data, end);
	  data = display_block (data, uvalue, end, ' ');
	  break;

	  /* GNU extensions.  */
	case DW_OP_GNU_push_tls_address:
	  printf (_("DW_OP_GNU_push_tls_address or DW_OP_HP_unknown"));
	  break;
	case DW_OP_GNU_uninit:
	  printf ("DW_OP_GNU_uninit");
	  /* FIXME: Is there data associated with this OP ?  */
	  break;
	case DW_OP_GNU_encoded_addr:
	  {
	    int encoding = 0;
	    dwarf_vma addr;

	    if (data < end)
	      encoding = *data++;
	    addr = get_encoded_value (&data, encoding, section, end);

	    printf ("DW_OP_GNU_encoded_addr: fmt:%02x addr:", encoding);
	    print_dwarf_vma (addr, pointer_size);
	  }
	  break;
	case DW_OP_implicit_pointer:
	case DW_OP_GNU_implicit_pointer:
	  /* FIXME: Strictly speaking for 64-bit DWARF3 files
	     this ought to be an 8-byte wide computation.  */
	  if (dwarf_version == -1)
	    {
	      printf (_("(%s in frame info)"),
		      (op == DW_OP_implicit_pointer
		       ? "DW_OP_implicit_pointer"
		       : "DW_OP_GNU_implicit_pointer"));
	      /* No way to tell where the next op is, so just bail.  */
	      return need_frame_base;
	    }
	  if (dwarf_version == 2)
	    {
	      SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
	    }
	  else
	    {
	      SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
	    }
	  READ_SLEB (svalue, data, end);
	  printf ("%s: <0x%s> %s",
		  (op == DW_OP_implicit_pointer
		   ? "DW_OP_implicit_pointer" : "DW_OP_GNU_implicit_pointer"),
		  dwarf_vmatoa ("x", uvalue),
		  dwarf_vmatoa ("d", svalue));
	  break;
	case DW_OP_entry_value:
	case DW_OP_GNU_entry_value:
	  READ_ULEB (uvalue, data, end);
	  /* PR 17531: file: 0cc9cd00.  */
	  if (uvalue > (dwarf_vma) (end - data))
	    uvalue = end - data;
	  printf ("%s: (", (op == DW_OP_entry_value ? "DW_OP_entry_value"
						    : "DW_OP_GNU_entry_value"));
	  if (decode_location_expression (data, pointer_size, offset_size,
					  dwarf_version, uvalue,
					  cu_offset, section))
	    need_frame_base = 1;
	  putchar (')');
	  data += uvalue;
	  break;
	case DW_OP_const_type:
	case DW_OP_GNU_const_type:
	  READ_ULEB (uvalue, data, end);
	  printf ("%s: <0x%s> ",
		  (op == DW_OP_const_type ? "DW_OP_const_type"
					  : "DW_OP_GNU_const_type"),
		  dwarf_vmatoa ("x", cu_offset + uvalue));
	  SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
	  data = display_block (data, uvalue, end, ' ');
	  break;
	case DW_OP_regval_type:
	case DW_OP_GNU_regval_type:
	  READ_ULEB (uvalue, data, end);
	  printf ("%s: %s (%s)",
		  (op == DW_OP_regval_type ? "DW_OP_regval_type"
					   : "DW_OP_GNU_regval_type"),
		  dwarf_vmatoa ("u", uvalue), regname (uvalue, 1));
	  READ_ULEB (uvalue, data, end);
	  printf (" <0x%s>", dwarf_vmatoa ("x", cu_offset + uvalue));
	  break;
	case DW_OP_deref_type:
	case DW_OP_GNU_deref_type:
	  SAFE_BYTE_GET_AND_INC (uvalue, data, 1, end);
	  printf ("%s: %ld",
		  (op == DW_OP_deref_type ? "DW_OP_deref_type"
					  : "DW_OP_GNU_deref_type"),
		  (long) uvalue);
	  READ_ULEB (uvalue, data, end);
	  printf (" <0x%s>", dwarf_vmatoa ("x", cu_offset + uvalue));
	  break;
	case DW_OP_convert:
	case DW_OP_GNU_convert:
	  READ_ULEB (uvalue, data, end);
	  printf ("%s <0x%s>",
		  (op == DW_OP_convert ? "DW_OP_convert" : "DW_OP_GNU_convert"),
		  dwarf_vmatoa ("x", uvalue ? cu_offset + uvalue : 0));
	  break;
	case DW_OP_reinterpret:
	case DW_OP_GNU_reinterpret:
	  READ_ULEB (uvalue, data, end);
	  printf ("%s <0x%s>",
		  (op == DW_OP_reinterpret ? "DW_OP_reinterpret"
					   : "DW_OP_GNU_reinterpret"),
		  dwarf_vmatoa ("x", uvalue ? cu_offset + uvalue : 0));
	  break;
	case DW_OP_GNU_parameter_ref:
	  SAFE_BYTE_GET_AND_INC (uvalue, data, 4, end);
	  printf ("DW_OP_GNU_parameter_ref: <0x%s>",
		  dwarf_vmatoa ("x", cu_offset + uvalue));
	  break;
	case DW_OP_addrx:
	  READ_ULEB (uvalue, data, end);
	  printf ("DW_OP_addrx <0x%s>", dwarf_vmatoa ("x", uvalue));
	  break;
	case DW_OP_GNU_addr_index:
	  READ_ULEB (uvalue, data, end);
	  printf ("DW_OP_GNU_addr_index <0x%s>", dwarf_vmatoa ("x", uvalue));
	  break;
	case DW_OP_GNU_const_index:
	  READ_ULEB (uvalue, data, end);
	  printf ("DW_OP_GNU_const_index <0x%s>", dwarf_vmatoa ("x", uvalue));
	  break;
	case DW_OP_GNU_variable_value:
	  /* FIXME: Strictly speaking for 64-bit DWARF3 files
	     this ought to be an 8-byte wide computation.  */
	  if (dwarf_version == -1)
	    {
	      printf (_("(DW_OP_GNU_variable_value in frame info)"));
	      /* No way to tell where the next op is, so just bail.  */
	      return need_frame_base;
	    }
	  if (dwarf_version == 2)
	    {
	      SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
	    }
	  else
	    {
	      SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
	    }
	  printf ("DW_OP_GNU_variable_value: <0x%s>", dwarf_vmatoa ("x", uvalue));
	  break;

	  /* HP extensions.  */
	case DW_OP_HP_is_value:
	  printf ("DW_OP_HP_is_value");
	  /* FIXME: Is there data associated with this OP ?  */
	  break;
	case DW_OP_HP_fltconst4:
	  printf ("DW_OP_HP_fltconst4");
	  /* FIXME: Is there data associated with this OP ?  */
	  break;
	case DW_OP_HP_fltconst8:
	  printf ("DW_OP_HP_fltconst8");
	  /* FIXME: Is there data associated with this OP ?  */
	  break;
	case DW_OP_HP_mod_range:
	  printf ("DW_OP_HP_mod_range");
	  /* FIXME: Is there data associated with this OP ?  */
	  break;
	case DW_OP_HP_unmod_range:
	  printf ("DW_OP_HP_unmod_range");
	  /* FIXME: Is there data associated with this OP ?  */
	  break;
	case DW_OP_HP_tls:
	  printf ("DW_OP_HP_tls");
	  /* FIXME: Is there data associated with this OP ?  */
	  break;

	  /* PGI (STMicroelectronics) extensions.  */
	case DW_OP_PGI_omp_thread_num:
	  /* Pushes the thread number for the current thread as it would be
	     returned by the standard OpenMP library function:
	     omp_get_thread_num().  The "current thread" is the thread for
	     which the expression is being evaluated.  */
	  printf ("DW_OP_PGI_omp_thread_num");
	  break;

	default:
	  if (op >= DW_OP_lo_user
	      && op <= DW_OP_hi_user)
	    printf (_("(User defined location op 0x%x)"), op);
	  else
	    printf (_("(Unknown location op 0x%x)"), op);
	  /* No way to tell where the next op is, so just bail.  */
	  return need_frame_base;
	}

      /* Separate the ops.  */
      if (data < end)
	printf ("; ");
    }

  return need_frame_base;
}


add_separate_debug_file (const char * filename, void * handle)
{
  separate_info * i = xmalloc (sizeof * i);

  i->filename = filename;
  i->handle   = handle;
  i->next     = first_separate_info;
  first_separate_info = i;
}


load_build_id_debug_file (const char * main_filename ATTRIBUTE_UNUSED, void * main_file)
{
  if (! load_debug_section (note_gnu_build_id, main_file))
    return; /* No .note.gnu.build-id section.  */

  struct dwarf_section * section = & debug_displays [note_gnu_build_id].section;
  if (section == NULL)
    {
      warn (_("Unable to load the .note.gnu.build-id section\n"));
      return;
    }

  if (section->start == NULL || section->size < 0x18)
    {
      warn (_(".note.gnu.build-id section is corrupt/empty\n"));
      return;
    }

  /* In theory we should extract the contents of the section into
     a note structure and then check the fields.  For now though
     just use hard coded offsets instead:

       Field  Bytes    Contents
	NSize  0...3   4
	DSize  4...7   8+
	Type   8..11   3  (NT_GNU_BUILD_ID)
        Name   12.15   GNU\0
	Data   16....   */

  /* FIXME: Check the name size, name and type fields.  */

  unsigned long build_id_size;
  build_id_size = byte_get (section->start + 4, 4);
  if (build_id_size < 8)
    {
      warn (_(".note.gnu.build-id data size is too small\n"));
      return;
    }

  if (build_id_size > (section->size - 16))
    {
      warn (_(".note.gnu.build-id data size is too bug\n"));
      return;
    }

  char * filename;
  filename = xmalloc (strlen (".build-id/")
		      + build_id_size * 2 + 2
		      + strlen (".debug")
		      /* The next string should be the same as the longest
			 name found in the prefixes[] array below.  */
		      + strlen ("/usrlib64/debug/usr")
		      + 1);
  void * handle;

  static const char * prefixes[] =
    {
      "",
      ".debug/",
      "/usr/lib/debug/",
      "/usr/lib/debug/usr/",
      "/usr/lib64/debug/",
      "/usr/lib64/debug/usr"
    };
  long unsigned int i;

  for (i = 0; i < ARRAY_SIZE (prefixes); i++)
    {
      handle = try_build_id_prefix (prefixes[i], filename,
				    section->start + 16, build_id_size);
      if (handle != NULL)
	break;
    }
  /* FIXME: TYhe BFD library also tries a global debugfile directory prefix.  */
  if (handle == NULL)
    {
      /* Failed to find a debug file associated with the build-id.
	 This is not an error however, rather it just means that
	 the debug info has probably not been loaded on the system,
	 or that another method is being used to link to the debug
	 info.  */
      free (filename);
      return;
    }

  add_separate_debug_file (filename, handle);
}


fetch_indexed_value (dwarf_vma idx,
		     enum dwarf_section_display_enum sec_enum,
		     dwarf_vma base_address)
{
  struct dwarf_section *section = &debug_displays [sec_enum].section;

  if (section->start == NULL)
    {
      warn (_("Unable to locate %s section\n"), section->uncompressed_name);
      return 0;
    }

  uint32_t pointer_size, bias;

  if (byte_get (section->start, 4) == 0xffffffff)
    {
      pointer_size = 8;
      bias = 20;
    }
  else
    {
      pointer_size = 4;
      bias = 12;
    }

  dwarf_vma offset = idx * pointer_size;

  /* Offsets are biased by the size of the section header
     or base address.  */
  if (sec_enum == loclists)
    offset += base_address;
  else
    offset += bias;

  if (offset + pointer_size > section->size)
    {
      warn (_("Offset into section %s too big: 0x%s\n"),
	    section->name, dwarf_vmatoa ("x", offset));
      return 0;
    }

  return byte_get (section->start + offset, pointer_size);
}


get_TAG_name (unsigned long tag)
{
  const char *name = get_DW_TAG_name ((unsigned int) tag);

  if (name == NULL)
    {
      static char buffer[100];

      if (tag >= DW_TAG_lo_user && tag <= DW_TAG_hi_user)
	snprintf (buffer, sizeof (buffer), _("User TAG value: %#lx"), tag);
      else
	snprintf (buffer, sizeof (buffer), _("Unknown TAG value: %#lx"), tag);
      return buffer;
    }

  return name;
}


reset_state_machine (int is_stmt)
{
  state_machine_regs.address = 0;
  state_machine_regs.view = 0;
  state_machine_regs.op_index = 0;
  state_machine_regs.file = 1;
  state_machine_regs.line = 1;
  state_machine_regs.column = 0;
  state_machine_regs.is_stmt = is_stmt;
  state_machine_regs.basic_block = 0;
  state_machine_regs.end_sequence = 0;
  state_machine_regs.last_file_entry = 0;
}


introduce (struct dwarf_section * section, bool raw)
{
  if (raw)
    {
      if (do_follow_links && section->filename)
	printf (_("Raw dump of debug contents of section %s (loaded from %s):\n\n"),
		section->name, section->filename);
      else
	printf (_("Raw dump of debug contents of section %s:\n\n"), section->name);
    }
  else
    {
      if (do_follow_links && section->filename)
	printf (_("Contents of the %s section (loaded from %s):\n\n"),
		section->name, section->filename);
      else
	printf (_("Contents of the %s section:\n\n"), section->name);
    }
}


cmalloc (size_t nmemb, size_t size)
{
  /* Check for overflow.  */
  if (nmemb >= ~(size_t) 0 / size)
    return NULL;

  return xmalloc (nmemb * size);
}


load_separate_debug_files (void * file, const char * filename)
{
  /* Skip this operation if we are not interested in debug links.  */
  if (! do_follow_links && ! do_debug_links)
    return false;

  /* See if there are any dwo links.  */
  if (load_debug_section (str, file)
      && load_debug_section (abbrev, file)
      && load_debug_section (info, file))
    {
      /* Load the .debug_addr section, if it exists.  */
      load_debug_section (debug_addr, file);
      /* Load the .debug_str_offsets section, if it exists.  */
      load_debug_section (str_index, file);

      free_dwo_info ();

      if (process_debug_info (& debug_displays[info].section, file, abbrev,
			      true, false))
	{
	  bool introduced = false;
	  dwo_info *dwinfo;
	  const char *dir = NULL;
	  const char *id = NULL;
	  const char *name = NULL;

	  for (dwinfo = first_dwo_info; dwinfo != NULL; dwinfo = dwinfo->next)
	    {
	      /* Accumulate NAME, DIR and ID fields.  */
	      switch (dwinfo->type)
		{
		case DWO_NAME:
		  if (name != NULL)
		    warn (_("Multiple DWO_NAMEs encountered for the same CU\n"));
		  name = dwinfo->value;
		  break;

		case DWO_DIR:
		  /* There can be multiple DW_AT_comp_dir entries in a CU,
		     so do not complain.  */
		  dir = dwinfo->value;
		  break;

		case DWO_ID:
		  if (id != NULL)
		    warn (_("multiple DWO_IDs encountered for the same CU\n"));
		  id = dwinfo->value;
		  break;

		default:
		  error (_("Unexpected DWO INFO type"));
		  break;
		}

	      /* If we have reached the end of our list, or we are changing
		 CUs, then display the information that we have accumulated
		 so far.  */
	      if (name != NULL
		  && (dwinfo->next == NULL
		      || dwinfo->next->cu_offset != dwinfo->cu_offset))
		{
		  if (do_debug_links)
		    {
		      if (! introduced)
			{
			  printf (_("The %s section contains link(s) to dwo file(s):\n\n"),
				  debug_displays [info].section.uncompressed_name);
			  introduced = true;
			}

		      printf (_("  Name:      %s\n"), name);
		      printf (_("  Directory: %s\n"), dir ? dir : _("<not-found>"));
		      if (id != NULL)
			display_data (printf (_("  ID:       ")), (unsigned char *) id, 8);
		      else
			printf (_("  ID:        <not specified>\n"));
		      printf ("\n\n");
		    }

		  if (do_follow_links)
		    load_dwo_file (filename, name, dir, id);

		  name = dir = id = NULL;
		}
	    }
	}
    }

  if (! do_follow_links)
    /* The other debug links will be displayed by display_debug_links()
       so we do not need to do any further processing here.  */
    return false;

  /* FIXME: We do not check for the presence of both link sections in the same file.  */
  /* FIXME: We do not check for the presence of multiple, same-name debuglink sections.  */
  /* FIXME: We do not check for the presence of a dwo link as well as a debuglink.  */

  check_for_and_load_links (file, filename);
  if (first_separate_info != NULL)
    return true;

  do_follow_links = 0;
  return false;
}


comp_addr_base (const void * v0, const void * v1)
{
  debug_info *info0 = *(debug_info **) v0;
  debug_info *info1 = *(debug_info **) v1;
  return info0->addr_base - info1->addr_base;
}


size_of_encoded_value (int encoding)
{
  switch (encoding & 0x7)
    {
    default:	/* ??? */
    case 0:	return eh_addr_size;
    case 2:	return 2;
    case 3:	return 4;
    case 4:	return 8;
    }
}


init_dwarf_regnames_i386 (void)
{
  dwarf_regnames = dwarf_regnames_i386;
  dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_i386);
  dwarf_regnames_lookup_func = regname_internal_by_table_only;
}


get_type_abbrev_from_form (unsigned long form,
			   unsigned long uvalue,
			   dwarf_vma cu_offset,
			   unsigned char *cu_end,
			   const struct dwarf_section *section,
			   unsigned long *abbrev_num_return,
			   unsigned char **data_return,
			   abbrev_map **map_return)
{
  unsigned long   abbrev_number;
  abbrev_map *    map;
  abbrev_entry *  entry;
  unsigned char * data;

  if (abbrev_num_return != NULL)
    * abbrev_num_return = 0;
  if (data_return != NULL)
    * data_return = NULL;

  switch (form)
    {
    case DW_FORM_GNU_ref_alt:
    case DW_FORM_ref_sig8:
      /* FIXME: We are unable to handle this form at the moment.  */
      return NULL;

    case DW_FORM_ref_addr:
      if (uvalue >= section->size)
	{
	  warn (_("Unable to resolve ref_addr form: uvalue %lx > section size %lx (%s)\n"),
		uvalue, (long) section->size, section->name);
	  return NULL;
	}
      break;

    case DW_FORM_ref_sup4:
    case DW_FORM_ref_sup8:
      break;

    case DW_FORM_ref1:
    case DW_FORM_ref2:
    case DW_FORM_ref4:
    case DW_FORM_ref8:
    case DW_FORM_ref_udata:
      if (uvalue + cu_offset > (size_t) (cu_end - section->start))
	{
	  warn (_("Unable to resolve ref form: uvalue %lx + cu_offset %lx > CU size %lx\n"),
		uvalue, (long) cu_offset, (long) (cu_end - section->start));
	  return NULL;
	}
      uvalue += cu_offset;
      break;

      /* FIXME: Are there other DW_FORMs that can be used by types ?  */

    default:
      warn (_("Unexpected form %lx encountered whilst finding abbreviation for type\n"), form);
      return NULL;
    }

  data = (unsigned char *) section->start + uvalue;
  map = find_abbrev_map_by_offset (uvalue);

  if (map == NULL)
    {
      warn (_("Unable to find abbreviations for CU offset %#lx\n"), uvalue);
      return NULL;
    }
  if (map->list == NULL)
    {
      warn (_("Empty abbreviation list encountered for CU offset %lx\n"), uvalue);
      return NULL;
    }

  if (map_return != NULL)
    {
      if (form == DW_FORM_ref_addr)
	*map_return = map;
      else
	*map_return = NULL;
    }

  READ_ULEB (abbrev_number, data, section->start + section->size);

  for (entry = map->list->first_abbrev; entry != NULL; entry = entry->next)
    if (entry->number == abbrev_number)
      break;

  if (abbrev_num_return != NULL)
    * abbrev_num_return = abbrev_number;

  if (data_return != NULL)
    * data_return = data;

  if (entry == NULL)
    warn (_("Unable to find entry for abbreviation %lu\n"), abbrev_number);

  return entry;
}


display_formatted_table (unsigned char *data,
			 unsigned char *start,
			 unsigned char *end,
			 const DWARF2_Internal_LineInfo *linfo,
			 struct dwarf_section *section,
			 bool is_dir)
{
  unsigned char *format_start, format_count, *format, formati;
  dwarf_vma data_count, datai;
  unsigned int namepass, last_entry = 0;
  const char * table_name = is_dir ? N_("Directory Table") : N_("File Name Table");

  SAFE_BYTE_GET_AND_INC (format_count, data, 1, end);
  if (do_checks && format_count > 5)
    warn (_("Unexpectedly large number of columns in the %s (%u)\n"),
	  table_name, format_count);

  format_start = data;
  for (formati = 0; formati < format_count; formati++)
    {
      SKIP_ULEB (data, end);
      SKIP_ULEB (data, end);
      if (data >= end)
	{
	  warn (_("%s: Corrupt format description entry\n"), table_name);
	  return data;
	}
    }

  READ_ULEB (data_count, data, end);
  if (data_count == 0)
    {
      printf (_("\n The %s is empty.\n"), table_name);
      return data;
    }
  else if (data >= end)
    {
      warn (_("%s: Corrupt entry count - expected %s but none found\n"),
	    table_name, dwarf_vmatoa ("x", data_count));
      return data;
    }

  else if (format_count == 0)
    {
      warn (_("%s: format count is zero, but the table is not empty\n"),
	    table_name);
      return end;
    }

  printf (_("\n The %s (offset 0x%lx, lines %s, columns %u):\n"),
	  table_name, (long) (data - start), dwarf_vmatoa ("u", data_count),
	  format_count);

  printf (_("  Entry"));
  /* Delay displaying name as the last entry for better screen layout.  */
  for (namepass = 0; namepass < 2; namepass++)
    {
      format = format_start;
      for (formati = 0; formati < format_count; formati++)
	{
	  dwarf_vma content_type;

	  READ_ULEB (content_type, format, end);
	  if ((content_type == DW_LNCT_path) == (namepass == 1))
	    switch (content_type)
	      {
	      case DW_LNCT_path:
		printf (_("\tName"));
		break;
	      case DW_LNCT_directory_index:
		printf (_("\tDir"));
		break;
	      case DW_LNCT_timestamp:
		printf (_("\tTime"));
		break;
	      case DW_LNCT_size:
		printf (_("\tSize"));
		break;
	      case DW_LNCT_MD5:
		printf (_("\tMD5\t\t\t"));
		break;
	      default:
		printf (_("\t(Unknown format content type %s)"),
			dwarf_vmatoa ("u", content_type));
	      }
	  SKIP_ULEB (format, end);
	}
    }
  putchar ('\n');

  for (datai = 0; datai < data_count; datai++)
    {
      unsigned char *datapass = data;

      printf ("  %d", last_entry++);
      /* Delay displaying name as the last entry for better screen layout.  */
      for (namepass = 0; namepass < 2; namepass++)
	{
	  format = format_start;
	  data = datapass;
	  for (formati = 0; formati < format_count; formati++)
	    {
	      dwarf_vma content_type, form;

	      READ_ULEB (content_type, format, end);
	      READ_ULEB (form, format, end);
	      data = read_and_display_attr_value (0, form, 0, start, data, end,
						  0, 0, linfo->li_offset_size,
						  linfo->li_version, NULL,
			    ((content_type == DW_LNCT_path) != (namepass == 1)),
						  section, NULL, '\t', -1);
	    }
	}

      if (data >= end && (datai < data_count - 1))
	{
	  warn (_("\n%s: Corrupt entries list\n"), table_name);
	  return data;
	}
      putchar ('\n');
    }
  return data;
}


process_cu_tu_index (struct dwarf_section *section, int do_display)
{
  unsigned char *phdr = section->start;
  unsigned char *limit = phdr + section->size;
  unsigned char *phash;
  unsigned char *pindex;
  unsigned char *ppool;
  unsigned int version;
  unsigned int ncols = 0;
  unsigned int nused;
  unsigned int nslots;
  unsigned int i;
  unsigned int j;
  dwarf_vma signature;
  size_t total;

  /* PR 17512: file: 002-168123-0.004.  */
  if (phdr == NULL)
    {
      warn (_("Section %s is empty\n"), section->name);
      return 0;
    }
  /* PR 17512: file: 002-376-0.004.  */
  if (section->size < 24)
    {
      warn (_("Section %s is too small to contain a CU/TU header\n"),
	    section->name);
      return 0;
    }

  phash = phdr;
  SAFE_BYTE_GET_AND_INC (version, phash, 4, limit);
  if (version >= 2)
    SAFE_BYTE_GET_AND_INC (ncols, phash, 4, limit);
  SAFE_BYTE_GET_AND_INC (nused, phash, 4, limit);
  SAFE_BYTE_GET_AND_INC (nslots, phash, 4, limit);

  pindex = phash + (size_t) nslots * 8;
  ppool = pindex + (size_t) nslots * 4;

  if (do_display)
    {
      introduce (section, false);

      printf (_("  Version:                 %u\n"), version);
      if (version >= 2)
	printf (_("  Number of columns:       %u\n"), ncols);
      printf (_("  Number of used entries:  %u\n"), nused);
      printf (_("  Number of slots:         %u\n\n"), nslots);
    }

  /* PR 17531: file: 45d69832.  */
  if (_mul_overflow ((size_t) nslots, 12, &total)
      || total > (size_t) (limit - phash))
    {
      warn (ngettext ("Section %s is too small for %u slot\n",
		      "Section %s is too small for %u slots\n",
		      nslots),
	    section->name, nslots);
      return 0;
    }

  if (version == 1)
    {
      if (!do_display)
	prealloc_cu_tu_list ((limit - ppool) / 4);
      for (i = 0; i < nslots; i++)
	{
	  unsigned char *shndx_list;
	  unsigned int shndx;

	  SAFE_BYTE_GET (signature, phash, 8, limit);
	  if (signature != 0)
	    {
	      SAFE_BYTE_GET (j, pindex, 4, limit);
	      shndx_list = ppool + j * 4;
	      /* PR 17531: file: 705e010d.  */
	      if (shndx_list < ppool)
		{
		  warn (_("Section index pool located before start of section\n"));
		  return 0;
		}

	      if (do_display)
		printf (_("  [%3d] Signature:  0x%s  Sections: "),
			i, dwarf_vmatoa ("x", signature));
	      for (;;)
		{
		  if (shndx_list >= limit)
		    {
		      warn (_("Section %s too small for shndx pool\n"),
			    section->name);
		      return 0;
		    }
		  SAFE_BYTE_GET (shndx, shndx_list, 4, limit);
		  if (shndx == 0)
		    break;
		  if (do_display)
		    printf (" %d", shndx);
		  else
		    add_shndx_to_cu_tu_entry (shndx);
		  shndx_list += 4;
		}
	      if (do_display)
		printf ("\n");
	      else
		end_cu_tu_entry ();
	    }
	  phash += 8;
	  pindex += 4;
	}
    }
  else if (version == 2)
    {
      unsigned int val;
      unsigned int dw_sect;
      unsigned char *ph = phash;
      unsigned char *pi = pindex;
      unsigned char *poffsets = ppool + (size_t) ncols * 4;
      unsigned char *psizes = poffsets + (size_t) nused * ncols * 4;
      bool is_tu_index;
      struct cu_tu_set *this_set = NULL;
      unsigned int row;
      unsigned char *prow;
      size_t temp;

      is_tu_index = strcmp (section->name, ".debug_tu_index") == 0;

      /* PR 17531: file: 0dd159bf.
	 Check for integer overflow (can occur when size_t is 32-bit)
	 with overlarge ncols or nused values.  */
      if (nused == -1u
	  || _mul_overflow ((size_t) ncols, 4, &temp)
	  || _mul_overflow ((size_t) nused + 1, temp, &total)
	  || total > (size_t) (limit - ppool))
	{
	  warn (_("Section %s too small for offset and size tables\n"),
		section->name);
	  return 0;
	}

      if (do_display)
	{
	  printf (_("  Offset table\n"));
	  printf ("  slot  %-16s  ",
		 is_tu_index ? _("signature") : _("dwo_id"));
	}
      else
	{
	  if (is_tu_index)
	    {
	      tu_count = nused;
	      tu_sets = xcalloc2 (nused, sizeof (struct cu_tu_set));
	      this_set = tu_sets;
	    }
	  else
	    {
	      cu_count = nused;
	      cu_sets = xcalloc2 (nused, sizeof (struct cu_tu_set));
	      this_set = cu_sets;
	    }
	}

      if (do_display)
	{
	  for (j = 0; j < ncols; j++)
	    {
	      unsigned char *p = ppool + j * 4;
	      SAFE_BYTE_GET (dw_sect, p, 4, limit);
	      printf (" %8s", get_DW_SECT_short_name (dw_sect));
	    }
	  printf ("\n");
	}

      for (i = 0; i < nslots; i++)
	{
	  SAFE_BYTE_GET (signature, ph, 8, limit);

	  SAFE_BYTE_GET (row, pi, 4, limit);
	  if (row != 0)
	    {
	      /* PR 17531: file: a05f6ab3.  */
	      if (row > nused)
		{
		  warn (_("Row index (%u) is larger than number of used entries (%u)\n"),
			row, nused);
		  return 0;
		}

	      if (!do_display)
		{
		  size_t num_copy = sizeof (uint64_t);

		  memcpy (&this_set[row - 1].signature, ph, num_copy);
		}

	      prow = poffsets + (row - 1) * ncols * 4;
	      if (do_display)
		printf (_("  [%3d] 0x%s"),
			i, dwarf_vmatoa ("x", signature));
	      for (j = 0; j < ncols; j++)
		{
		  unsigned char *p = prow + j * 4;
		  SAFE_BYTE_GET (val, p, 4, limit);
		  if (do_display)
		    printf (" %8d", val);
		  else
		    {
		      p = ppool + j * 4;
		      SAFE_BYTE_GET (dw_sect, p, 4, limit);

		      /* PR 17531: file: 10796eb3.  */
		      if (dw_sect >= DW_SECT_MAX)
			warn (_("Overlarge Dwarf section index detected: %u\n"), dw_sect);
		      else
			this_set [row - 1].section_offsets [dw_sect] = val;
		    }
		}

	      if (do_display)
		printf ("\n");
	    }
	  ph += 8;
	  pi += 4;
	}

      ph = phash;
      pi = pindex;
      if (do_display)
	{
	  printf ("\n");
	  printf (_("  Size table\n"));
	  printf ("  slot  %-16s  ",
		 is_tu_index ? _("signature") : _("dwo_id"));
	}

      for (j = 0; j < ncols; j++)
	{
	  unsigned char *p = ppool + j * 4;
	  SAFE_BYTE_GET (val, p, 4, limit);
	  if (do_display)
	    printf (" %8s", get_DW_SECT_short_name (val));
	}

      if (do_display)
	printf ("\n");

      for (i = 0; i < nslots; i++)
	{
	  SAFE_BYTE_GET (signature, ph, 8, limit);

	  SAFE_BYTE_GET (row, pi, 4, limit);
	  if (row != 0)
	    {
	      prow = psizes + (row - 1) * ncols * 4;

	      if (do_display)
		printf (_("  [%3d] 0x%s"),
			i, dwarf_vmatoa ("x", signature));

	      for (j = 0; j < ncols; j++)
		{
		  unsigned char *p = prow + j * 4;

		  /* PR 28645: Check for overflow.  Since we do not know how
		     many populated rows there will be, we cannot just
		     perform a single check at the start of this function.  */
		  if (p > (limit - 4))
		    {
		      if (do_display)
			printf ("\n");
		      warn (_("Too many rows/columns in DWARF index section %s\n"),
			    section->name);
		      return 0;
		    }

		  SAFE_BYTE_GET (val, p, 4, limit);

		  if (do_display)
		    printf (" %8d", val);
		  else
		    {
		      p = ppool + j * 4;
		      SAFE_BYTE_GET (dw_sect, p, 4, limit);
		      if (dw_sect >= DW_SECT_MAX)
			warn (_("Overlarge Dwarf section index detected: %u\n"), dw_sect);
		      else
		      this_set [row - 1].section_sizes [dw_sect] = val;
		    }
		}

	      if (do_display)
		printf ("\n");
	    }

	  ph += 8;
	  pi += 4;
	}
    }
  else if (do_display)
    printf (_("  Unsupported version (%d)\n"), version);

  if (do_display)
      printf ("\n");

  return 1;
}


fetch_indexed_addr (dwarf_vma offset, uint32_t num_bytes)
{
  struct dwarf_section *section = &debug_displays [debug_addr].section;

  if (section->start == NULL)
    {
      warn (_("<no .debug_addr section>"));
      return 0;
    }

  if (offset + num_bytes > section->size)
    {
      warn (_("Offset into section %s too big: 0x%s\n"),
	    section->name, dwarf_vmatoa ("x", offset));
      return 0;
    }

  return byte_get (section->start + offset, num_bytes);
}


display_offset_entry_loclists (struct dwarf_section *section)
{
  unsigned char *  start = section->start;
  unsigned char * const end = start + section->size;

  introduce (section, false);

  do
    {
      dwarf_vma        length;
      unsigned short   version;
      unsigned char    address_size;
      unsigned char    segment_selector_size;
      uint32_t         offset_entry_count;
      uint32_t         i;
      bool             is_64bit;

      printf (_("Table at Offset 0x%lx\n"), (long)(start - section->start));

      SAFE_BYTE_GET_AND_INC (length, start, 4, end);
      if (length == 0xffffffff)
	{
	  is_64bit = true;
	  SAFE_BYTE_GET_AND_INC (length, start, 8, end);
	}
      else
	is_64bit = false;

      SAFE_BYTE_GET_AND_INC (version, start, 2, end);
      SAFE_BYTE_GET_AND_INC (address_size, start, 1, end);
      SAFE_BYTE_GET_AND_INC (segment_selector_size, start, 1, end);
      SAFE_BYTE_GET_AND_INC (offset_entry_count, start, 4, end);

      printf (_("  Length:          0x%s\n"), dwarf_vmatoa ("x", length));
      printf (_("  DWARF version:   %u\n"), version);
      printf (_("  Address size:    %u\n"), address_size);
      printf (_("  Segment size:    %u\n"), segment_selector_size);
      printf (_("  Offset entries:  %u\n"), offset_entry_count);

      if (version < 5)
	{
	  warn (_("The %s section contains a corrupt or "
		  "unsupported version number: %d.\n"),
		section->name, version);
	  return 0;
	}

      if (segment_selector_size != 0)
	{
	  warn (_("The %s section contains an "
		  "unsupported segment selector size: %d.\n"),
		section->name, segment_selector_size);
	  return 0;
	}

      if (offset_entry_count == 0)
	{
	  warn (_("The %s section contains a table without offset\n"),
		section->name);
	  return 0;
	}

      printf (_("\n   Offset Entries starting at 0x%lx:\n"),
	      (long)(start - section->start));

      if (is_64bit)
	{
	  for (i = 0; i < offset_entry_count; i++)
	    {
	      dwarf_vma entry;

	      SAFE_BYTE_GET_AND_INC (entry, start, 8, end);
	      printf (_("    [%6u] 0x%s\n"), i, dwarf_vmatoa ("x", entry));
	    }
	}
      else
	{
	  for (i = 0; i < offset_entry_count; i++)
	    {
	      uint32_t entry;

	      SAFE_BYTE_GET_AND_INC (entry, start, 4, end);
	      printf (_("    [%6u] 0x%x\n"), i, entry);
	    }
	}

      putchar ('\n');

      uint32_t j;

      for (j = 1, i = 0; i < offset_entry_count;)
	{
	  unsigned char  lle;
	  dwarf_vma      base_address = 0;
	  dwarf_vma      begin;
	  dwarf_vma      finish;
	  dwarf_vma      off = start - section->start;

	  if (j != i)
	    {
	      printf (_("   Offset Entry %u\n"), i);
	      j = i;
	    }

	  printf ("    ");
	  print_dwarf_vma (off, 4);

	  SAFE_BYTE_GET_AND_INC (lle, start, 1, end);

	  switch (lle)
	    {
	    case DW_LLE_end_of_list:
	      printf (_("<End of list>\n\n"));
	      i ++;
	      continue;

	    case DW_LLE_base_addressx:
	      READ_ULEB (base_address, start, end);
	      print_dwarf_vma (base_address, address_size);
	      printf (_("(index into .debug_addr) "));
	      base_address = fetch_indexed_addr (base_address, address_size);
	      print_dwarf_vma (base_address, address_size);
	      printf (_("(base address)\n"));
	      continue;

	    case DW_LLE_startx_endx:
	      READ_ULEB (begin, start, end);
	      begin = fetch_indexed_addr (begin, address_size);
	      READ_ULEB (finish, start, end);
	      finish = fetch_indexed_addr (finish, address_size);
	      break;

	    case DW_LLE_startx_length:
	      READ_ULEB (begin, start, end);
	      begin = fetch_indexed_addr (begin, address_size);
	      READ_ULEB (finish, start, end);
	      finish += begin;
	      break;

	    case DW_LLE_offset_pair:
	      READ_ULEB (begin, start, end);
	      begin += base_address;
	      READ_ULEB (finish, start, end);
	      finish += base_address;
	      break;

	    case DW_LLE_default_location:
	      begin = finish = 0;
	      break;

	    case DW_LLE_base_address:
	      SAFE_BYTE_GET_AND_INC (base_address, start, address_size, end);
	      print_dwarf_vma (base_address, address_size);
	      printf (_("(base address)\n"));
	      continue;

	    case DW_LLE_start_end:
	      SAFE_BYTE_GET_AND_INC (begin,  start, address_size, end);
	      SAFE_BYTE_GET_AND_INC (finish, start, address_size, end);
	      break;

	    case DW_LLE_start_length:
	      SAFE_BYTE_GET_AND_INC (begin, start, address_size, end);
	      READ_ULEB (finish, start, end);
	      finish += begin;
	      break;

	    default:
	      error (_("Invalid location list entry type %d\n"), lle);
	      return 0;
	    }

	  if (start == end)
	    {
	      warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
		    (unsigned long) off);
	      break;
	    }

	  print_dwarf_vma (begin, address_size);
	  print_dwarf_vma (finish, address_size);

	  if (begin == finish)
	    fputs (_(" (start == end)"), stdout);
	  else if (begin > finish)
	    fputs (_(" (start > end)"), stdout);

	  /* Read the counted location descriptions.  */
	  READ_ULEB (length, start, end);

	  if (length > (size_t) (end - start))
	    {
	      warn (_("Location list starting at offset 0x%lx is not terminated.\n"),
		    (unsigned long) off);
	      break;
	    }

	  putchar (' ');
	  (void) decode_location_expression (start, address_size, address_size,
					     version, length, 0, section);
	  start += length;
	  putchar ('\n');
	}

      putchar ('\n');
    }
  while (start < end);

  return 1;
}


frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_regs)
{
  unsigned int r;
  char tmp[100];

  if (*max_regs != fc->ncols)
    *max_regs = fc->ncols;

  if (*need_col_headers)
    {
      *need_col_headers = 0;

      printf ("%-*s CFA      ", eh_addr_size * 2, "   LOC");

      for (r = 0; r < *max_regs; r++)
	if (fc->col_type[r] != DW_CFA_unreferenced)
	  {
	    if (r == fc->ra)
	      printf ("ra    ");
	    else
	      printf ("%-5s ", regname (r, 1));
	  }

      printf ("\n");
    }

  print_dwarf_vma (fc->pc_begin, eh_addr_size);
  if (fc->cfa_exp)
    strcpy (tmp, "exp");
  else
    sprintf (tmp, "%s%+d", regname (fc->cfa_reg, 1), (int) fc->cfa_offset);
  printf ("%-8s ", tmp);

  for (r = 0; r < fc->ncols; r++)
    {
      if (fc->col_type[r] != DW_CFA_unreferenced)
	{
	  switch (fc->col_type[r])
	    {
	    case DW_CFA_undefined:
	      strcpy (tmp, "u");
	      break;
	    case DW_CFA_same_value:
	      strcpy (tmp, "s");
	      break;
	    case DW_CFA_offset:
	      sprintf (tmp, "c%+d", fc->col_offset[r]);
	      break;
	    case DW_CFA_val_offset:
	      sprintf (tmp, "v%+d", fc->col_offset[r]);
	      break;
	    case DW_CFA_register:
	      sprintf (tmp, "%s", regname (fc->col_offset[r], 0));
	      break;
	    case DW_CFA_expression:
	      strcpy (tmp, "exp");
	      break;
	    case DW_CFA_val_expression:
	      strcpy (tmp, "vexp");
	      break;
	    default:
	      strcpy (tmp, "n/a");
	      break;
	    }
	  printf ("%-5s ", tmp);
	}
    }
  printf ("\n");
}


check_uvalue (const unsigned char * start,
	      dwarf_vma             uvalue,
	      const unsigned char * end)
{
  dwarf_vma max_uvalue = end - start;

  /* See PR 17512: file: 008-103549-0.001:0.1.
     and PR 24829 for examples of where these tests are triggered.  */
  if (uvalue > max_uvalue)
    {
      warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
      uvalue = max_uvalue;
    }

  return uvalue;
}


load_debug_sup_file (const char * main_filename, void * file)
{
  if (! load_debug_section (debug_sup, file))
    return; /* No .debug_sup section.  */

  struct dwarf_section * section;
  section = & debug_displays [debug_sup].section;
  assert (section != NULL);

  if (section->start == NULL || section->size < 5)
    {
      warn (_(".debug_sup section is corrupt/empty\n"));
      return;
    }

  if (section->start[2] != 0)
    return; /* This is a supplementary file.  */

  const char * filename = (const char *) section->start + 3;
  if (strnlen (filename, section->size - 3) == section->size - 3)
    {
      warn (_("filename in .debug_sup section is corrupt\n"));
      return;
    }

  if (filename[0] != '/' && strchr (main_filename, '/'))
    {
      char * new_name;
      int new_len;

      new_len = asprintf (& new_name, "%.*s/%s",
			  (int) (strrchr (main_filename, '/') - main_filename),
			  main_filename,
			  filename);
      if (new_len < 3)
	{
	  warn (_("unable to construct path for supplementary debug file"));
	  if (new_len > -1)
	    free (new_name);
	  return;
	}
      filename = new_name;
    }
  else
    {
      /* PR 27796: Make sure that we pass a filename that can be free'd to
	 add_separate_debug_file().  */
      filename = strdup (filename);
      if (filename == NULL)
	{
	  warn (_("out of memory constructing filename for .debug_sup link\n"));
	  return;
	}
    }

  void * handle = open_debug_file (filename);
  if (handle == NULL)
    {
      warn (_("unable to open file '%s' referenced from .debug_sup section\n"), filename);
      free ((void *) filename);
      return;
    }

  printf (_("%s: Found supplementary debug file: %s\n\n"), main_filename, filename);

  /* FIXME: Compare the checksums, if present.  */
  add_separate_debug_file (filename, handle);
}


display_discr_list (unsigned long          form,
		    dwarf_vma              uvalue,
		    unsigned char *        data,
		    int                    level)
{
  unsigned char *end = data;

  if (uvalue == 0)
    {
      printf ("[default]");
      return;
    }

  switch (form)
    {
    case DW_FORM_block:
    case DW_FORM_block1:
    case DW_FORM_block2:
    case DW_FORM_block4:
      /* Move data pointer back to the start of the byte array.  */
      data -= uvalue;
      break;
    default:
      printf ("<corrupt>\n");
      warn (_("corrupt discr_list - not using a block form\n"));
      return;
    }

  if (uvalue < 2)
    {
      printf ("<corrupt>\n");
      warn (_("corrupt discr_list - block not long enough\n"));
      return;
    }

  bool is_signed = (level > 0 && level <= MAX_CU_NESTING
		    ? level_type_signed [level - 1] : false);

  printf ("(");
  while (data < end)
    {
      unsigned char     discriminant;
      unsigned int      bytes_read;

      SAFE_BYTE_GET_AND_INC (discriminant, data, 1, end);

      switch (discriminant)
	{
	case DW_DSC_label:
	  printf ("label ");
	  read_and_print_leb128 (data, & bytes_read, end, is_signed);
	  data += bytes_read;
	  break;

	case DW_DSC_range:
	  printf ("range ");
	  read_and_print_leb128 (data, & bytes_read, end, is_signed);
	  data += bytes_read;

	  printf ("..");
	  read_and_print_leb128 (data, & bytes_read, end, is_signed);
	  data += bytes_read;
	  break;

	default:
	  printf ("<corrupt>\n");
	  warn (_("corrupt discr_list - unrecognized discriminant byte %#x\n"),
		discriminant);
	  return;
	}

      if (data < end)
	printf (", ");
    }

  if (is_signed)
    printf (")(signed)");
  else
    printf (")(unsigned)");
}


record_abbrev_list_for_cu (dwarf_vma start, dwarf_vma end, abbrev_list * list)
{
  if (cu_abbrev_map == NULL)
    {
      num_abbrev_map_entries = INITIAL_NUM_ABBREV_MAP_ENTRIES;
      cu_abbrev_map = xmalloc (num_abbrev_map_entries * sizeof (* cu_abbrev_map));
    }
  else if (next_free_abbrev_map_entry == num_abbrev_map_entries)
    {
      num_abbrev_map_entries += ABBREV_MAP_ENTRIES_INCREMENT;
      cu_abbrev_map = xrealloc (cu_abbrev_map, num_abbrev_map_entries * sizeof (* cu_abbrev_map));
    }

  cu_abbrev_map[next_free_abbrev_map_entry].start = start;
  cu_abbrev_map[next_free_abbrev_map_entry].end = end;
  cu_abbrev_map[next_free_abbrev_map_entry].list = list;
  next_free_abbrev_map_entry ++;
}


regname_internal_riscv (unsigned int regno)
{
  const char *name = NULL;

  /* Lookup in the table first, this covers GPR and FPR.  */
  if (regno < ARRAY_SIZE (dwarf_regnames_riscv))
    name = dwarf_regnames_riscv [regno];
  else if (regno >= 4096 && regno <= 8191)
    {
      /* This might be a CSR, these live in a sparse number space from 4096
	 to 8191  These numbers are defined in the RISC-V ELF ABI
	 document.  */
      switch (regno)
	{
#define DECLARE_CSR(NAME,VALUE,CLASS,DEFINE_VER,ABORT_VER) \
  case VALUE + 4096: name = #NAME; break;
#include "opcode/riscv-opc.h"
#undef DECLARE_CSR

	default:
	  {
	    static char csr_name[10];
	    snprintf (csr_name, sizeof (csr_name), "csr%d", (regno - 4096));
	    name = csr_name;
	  }
	  break;
	}
    }

  return name;
}


display_cu_index (struct dwarf_section *section, void *file ATTRIBUTE_UNUSED)
{
  return process_cu_tu_index (section, 1);
}


process_extended_line_op (unsigned char * data,
			  int is_stmt,
			  unsigned char * end)
{
  unsigned char op_code;
  size_t len, header_len;
  unsigned char *name;
  unsigned char *orig_data = data;
  dwarf_vma adr, val;

  READ_ULEB (len, data, end);
  header_len = data - orig_data;

  if (len == 0 || data >= end || len > (size_t) (end - data))
    {
      warn (_("Badly formed extended line op encountered!\n"));
      return header_len;
    }

  op_code = *data++;

  printf (_("  Extended opcode %d: "), op_code);

  switch (op_code)
    {
    case DW_LNE_end_sequence:
      printf (_("End of Sequence\n\n"));
      reset_state_machine (is_stmt);
      break;

    case DW_LNE_set_address:
      /* PR 17512: file: 002-100480-0.004.  */
      if (len - 1 > 8)
	{
	  warn (_("Length (%lu) of DW_LNE_set_address op is too long\n"),
		(unsigned long) len - 1);
	  adr = 0;
	}
      else
	SAFE_BYTE_GET (adr, data, len - 1, end);
      printf (_("set Address to 0x%s\n"), dwarf_vmatoa ("x", adr));
      state_machine_regs.address = adr;
      state_machine_regs.view = 0;
      state_machine_regs.op_index = 0;
      break;

    case DW_LNE_define_file:
      printf (_("define new File Table entry\n"));
      printf (_("  Entry\tDir\tTime\tSize\tName\n"));
      printf ("   %d\t", ++state_machine_regs.last_file_entry);

      {
	size_t l;

	name = data;
	l = strnlen ((char *) data, end - data);
	data += l;
	if (data < end)
	  data++;
	READ_ULEB (val, data, end);
	printf ("%s\t", dwarf_vmatoa ("u", val));
	READ_ULEB (val, data, end);
	printf ("%s\t", dwarf_vmatoa ("u", val));
	READ_ULEB (val, data, end);
	printf ("%s\t", dwarf_vmatoa ("u", val));
	printf ("%.*s\n\n", (int) l, name);
      }

      if (((size_t) (data - orig_data) != len + header_len) || data >= end)
	warn (_("DW_LNE_define_file: Bad opcode length\n"));
      break;

    case DW_LNE_set_discriminator:
      READ_ULEB (val, data, end);
      printf (_("set Discriminator to %s\n"), dwarf_vmatoa ("u", val));
      break;

    /* HP extensions.  */
    case DW_LNE_HP_negate_is_UV_update:
      printf ("DW_LNE_HP_negate_is_UV_update\n");
      break;
    case DW_LNE_HP_push_context:
      printf ("DW_LNE_HP_push_context\n");
      break;
    case DW_LNE_HP_pop_context:
      printf ("DW_LNE_HP_pop_context\n");
      break;
    case DW_LNE_HP_set_file_line_column:
      printf ("DW_LNE_HP_set_file_line_column\n");
      break;
    case DW_LNE_HP_set_routine_name:
      printf ("DW_LNE_HP_set_routine_name\n");
      break;
    case DW_LNE_HP_set_sequence:
      printf ("DW_LNE_HP_set_sequence\n");
      break;
    case DW_LNE_HP_negate_post_semantics:
      printf ("DW_LNE_HP_negate_post_semantics\n");
      break;
    case DW_LNE_HP_negate_function_exit:
      printf ("DW_LNE_HP_negate_function_exit\n");
      break;
    case DW_LNE_HP_negate_front_end_logical:
      printf ("DW_LNE_HP_negate_front_end_logical\n");
      break;
    case DW_LNE_HP_define_proc:
      printf ("DW_LNE_HP_define_proc\n");
      break;
    case DW_LNE_HP_source_file_correlation:
      {
	unsigned char *edata = data + len - 1;

	printf ("DW_LNE_HP_source_file_correlation\n");

	while (data < edata)
	  {
	    unsigned int opc;

	    READ_ULEB (opc, data, edata);

	    switch (opc)
	      {
	      case DW_LNE_HP_SFC_formfeed:
		printf ("    DW_LNE_HP_SFC_formfeed\n");
		break;
	      case DW_LNE_HP_SFC_set_listing_line:
		READ_ULEB (val, data, edata);
		printf ("    DW_LNE_HP_SFC_set_listing_line (%s)\n",
			dwarf_vmatoa ("u", val));
		break;
	      case DW_LNE_HP_SFC_associate:
		printf ("    DW_LNE_HP_SFC_associate ");
		READ_ULEB (val, data, edata);
		printf ("(%s", dwarf_vmatoa ("u", val));
		READ_ULEB (val, data, edata);
		printf (",%s", dwarf_vmatoa ("u", val));
		READ_ULEB (val, data, edata);
		printf (",%s)\n", dwarf_vmatoa ("u", val));
		break;
	      default:
		printf (_("    UNKNOWN DW_LNE_HP_SFC opcode (%u)\n"), opc);
		data = edata;
		break;
	      }
	  }
      }
      break;

    default:
      {
	unsigned int rlen = len - 1;

	if (op_code >= DW_LNE_lo_user
	    /* The test against DW_LNW_hi_user is redundant due to
	       the limited range of the unsigned char data type used
	       for op_code.  */
	    /*&& op_code <= DW_LNE_hi_user*/)
	  printf (_("user defined: "));
	else
	  printf (_("UNKNOWN: "));
	printf (_("length %d ["), rlen);
	for (; rlen; rlen--)
	  printf (" %02x", *data++);
	printf ("]\n");
      }
      break;
    }

  return len + header_len;
}


free_dwo_info (void)
{
  dwo_info * dwinfo;
  dwo_info * next;

  for (dwinfo = first_dwo_info; dwinfo != NULL; dwinfo = next)
    {
      next = dwinfo->next;
      free (dwinfo);
    }
  first_dwo_info = NULL;
}


display_debug_pubnames (struct dwarf_section *section, void *file)
{
  return display_debug_pubnames_worker (section, file, 0);
}