Esempio n. 1
0
static void remove_duplicate_nodes(struct call_graph *graph)
{
	int i = 0;
	int j = 0;

	qsort(graph->node_list.ptr, graph->node_list.size,
	      graph->node_list.elemsize, cmp_node);

	while (i < graph->node_list.size) {
		struct cg_node *n = CG_NODE(graph, i);
		struct cg_node *l = CG_NODE(graph, j - 1);

		if (!j || n->offset != l->offset) {
			if (i != j)
				memcpy(l + 1, n, sizeof(*l));
			j++;
		}

		i++;
	}

	graph->node_list.size = j;
}
Esempio n. 2
0
static void relabel_sources(struct call_graph *graph)
{
	int i = 0; /* Node index */
	int j = 0; /* Edge index */

	/* Identify the source nodes for each edge */
	qsort(graph->edge_from.ptr, graph->edge_from.size,
	      graph->edge_from.elemsize, cmp_branch_by_src);

	while (j < graph->edge_from.size) {
		struct cg_edge *br = CG_EDGE_FROM(graph, j);
		struct cg_node *n;

		/* Skip over nodes which are too early for this edge */
		while (i + 1 < graph->node_list.size &&
		       CG_NODE(graph, i + 1)->offset <= br->src)
			i++;

		n = CG_NODE(graph, i);
		if (n->offset <= br->src)
			br->src = n->offset;
		j++;
	}
}
Esempio n. 3
0
static void cgraph_summary(struct call_graph *graph)
{
	int i;
	int j = 0; /* Edge from index */
	int k = 0; /* Edge to index */

	for (i = 0; i < graph->node_list.size; i++) {
		struct cg_node *n = CG_NODE(graph, i);
		int from_count = 0;
		int to_count = 0;
		char name[64];

		while (j < graph->edge_from.size &&
		       CG_EDGE_FROM(graph, j)->src < n->offset)
			j++;

		while (k < graph->edge_to.size &&
		       CG_EDGE_TO(graph, k)->dst < n->offset)
			k++;

		while (j < graph->edge_from.size &&
		       CG_EDGE_FROM(graph, j)->src == n->offset) {
			from_count++;
			j++;
		}

		while (k < graph->edge_to.size &&
		       CG_EDGE_TO(graph, k)->dst == n->offset) {
			to_count++;
			k++;
		}

		print_address(n->offset, name, sizeof(name), 0);
		printc("0x%04x [%3d ==> %3d] %s\n",
		       n->offset, to_count, from_count, name);
	}
}
Esempio n. 4
0
static bool
dump_layer_cb(cg_node_t *node, void *user_data)
{
    cg_pipeline_layer_t *layer = CG_PIPELINE_LAYER(node);
    print_debug_state_t *state = user_data;
    int layer_id = *state->node_id_ptr;
    print_debug_state_t state_out;
    c_string_t *changes_label;
    bool changes = false;

    if (state->parent_id >= 0)
        c_string_append_printf(state->graph,
                               "%*slayer%p -> layer%p;\n",
                               state->indent,
                               "",
                               layer->_parent.parent,
                               layer);

    c_string_append_printf(state->graph,
                           "%*slayer%p [label=\"layer=0x%p\\n"
                           "ref count=%d\" "
                           "color=\"blue\"];\n",
                           state->indent,
                           "",
                           layer,
                           layer,
                           CG_OBJECT(layer)->ref_count);

    changes_label = c_string_new("");
    c_string_append_printf(changes_label,
                           "%*slayer%p -> layer_state%d [weight=100];\n"
                           "%*slayer_state%d [shape=box label=\"",
                           state->indent,
                           "",
                           layer,
                           layer_id,
                           state->indent,
                           "",
                           layer_id);

    if (layer->differences & CG_PIPELINE_LAYER_STATE_UNIT) {
        changes = true;
        c_string_append_printf(
            changes_label, "\\lunit=%u\\n", layer->unit_index);
    }

    if (layer->differences & CG_PIPELINE_LAYER_STATE_TEXTURE_DATA) {
        changes = true;
        c_string_append_printf(
            changes_label, "\\ltexture=%p\\n", layer->texture);
    }

    if (changes) {
        c_string_append_printf(changes_label, "\"];\n");
        c_string_append(state->graph, changes_label->str);
        c_string_free(changes_label, true);
    }

    state_out.parent_id = layer_id;

    state_out.node_id_ptr = state->node_id_ptr;
    (*state_out.node_id_ptr)++;

    state_out.graph = state->graph;
    state_out.indent = state->indent + 2;

    _cg_pipeline_node_foreach_child(CG_NODE(layer), dump_layer_cb, &state_out);

    return true;
}
Esempio n. 5
0
static bool
dump_pipeline_cb(cg_node_t *node, void *user_data)
{
    cg_pipeline_t *pipeline = CG_PIPELINE(node);
    print_debug_state_t *state = user_data;
    int pipeline_id = *state->node_id_ptr;
    print_debug_state_t state_out;
    c_string_t *changes_label;
    bool changes = false;
    bool layers = false;

    if (state->parent_id >= 0)
        c_string_append_printf(state->graph,
                               "%*spipeline%d -> pipeline%d;\n",
                               state->indent,
                               "",
                               state->parent_id,
                               pipeline_id);

    c_string_append_printf(state->graph,
                           "%*spipeline%d [label=\"pipeline=0x%p\\n"
                           "ref count=%d\\n"
                           "breadcrumb=\\\"%s\\\"\" color=\"red\"];\n",
                           state->indent,
                           "",
                           pipeline_id,
                           pipeline,
                           CG_OBJECT(pipeline)->ref_count,
                           pipeline->has_static_breadcrumb ?
#ifdef CG_DEBUG_ENABLED
                           pipeline->static_breadcrumb
                           : "NULL"
#else
                           "NULL"
#endif
                           );

    changes_label = c_string_new("");
    c_string_append_printf(changes_label,
                           "%*spipeline%d -> pipeline_state%d [weight=100];\n"
                           "%*spipeline_state%d [shape=box label=\"",
                           state->indent,
                           "",
                           pipeline_id,
                           pipeline_id,
                           state->indent,
                           "",
                           pipeline_id);

    if (pipeline->differences & CG_PIPELINE_STATE_COLOR) {
        changes = true;
        c_string_append_printf(changes_label,
                               "\\lcolor=0x%02X%02X%02X%02X\\n",
                               cg_color_get_red_byte(&pipeline->color),
                               cg_color_get_green_byte(&pipeline->color),
                               cg_color_get_blue_byte(&pipeline->color),
                               cg_color_get_alpha_byte(&pipeline->color));
    }

    if (pipeline->differences & CG_PIPELINE_STATE_BLEND) {
        const char *blend_enable_name;

        changes = true;

        switch (pipeline->blend_enable) {
        case CG_PIPELINE_BLEND_ENABLE_AUTOMATIC:
            blend_enable_name = "AUTO";
            break;
        case CG_PIPELINE_BLEND_ENABLE_ENABLED:
            blend_enable_name = "ENABLED";
            break;
        case CG_PIPELINE_BLEND_ENABLE_DISABLED:
            blend_enable_name = "DISABLED";
            break;
        default:
            blend_enable_name = "UNKNOWN";
        }
        c_string_append_printf(
            changes_label, "\\lblend=%s\\n", blend_enable_name);
    }

    if (pipeline->differences & CG_PIPELINE_STATE_LAYERS) {
        changes = true;
        layers = true;
        c_string_append_printf(
            changes_label, "\\ln_layers=%d\\n", pipeline->n_layers);
    }

    if (changes) {
        c_string_append_printf(changes_label, "\"];\n");
        c_string_append(state->graph, changes_label->str);
        c_string_free(changes_label, true);
    }

    if (layers) {
        c_llist_foreach(pipeline->layer_differences,
                       (c_iter_func_t)dump_layer_ref_cb, state);
    }

    state_out.parent_id = pipeline_id;

    state_out.node_id_ptr = state->node_id_ptr;
    (*state_out.node_id_ptr)++;

    state_out.graph = state->graph;
    state_out.indent = state->indent + 2;

    _cg_pipeline_node_foreach_child(
        CG_NODE(pipeline), dump_pipeline_cb, &state_out);

    return true;
}
Esempio n. 6
0
static void cgraph_func_info(struct call_graph *graph, address_t addr)
{
	int i = 0;
	int j = 0;
	int k = 0;
	char name[64];
	struct cg_node *n;

	while (i + 1 < graph->node_list.size &&
	       CG_NODE(graph, i + 1)->offset <= addr)
		i++;
	if (i >= graph->node_list.size ||
	    CG_NODE(graph, i)->offset > addr) {
		printc("No information for address 0x%04x\n", addr);
		return;
	}

	n = CG_NODE(graph, i);

	while (j < graph->edge_from.size &&
	       CG_EDGE_FROM(graph, j)->src < n->offset)
		j++;

	while (k < graph->edge_to.size &&
	       CG_EDGE_TO(graph, k)->dst < n->offset)
		k++;

	print_address(n->offset, name, sizeof(name), 0);
	printc("0x%04x %s:\n", n->offset, name);

	if (j < graph->edge_from.size &&
	    CG_EDGE_FROM(graph, j)->src == n->offset) {
		printc("    Callees:\n");
		while (j < graph->edge_from.size) {
			struct cg_edge *e = CG_EDGE_FROM(graph, j);

			if (e->src != n->offset)
				break;

			print_address(e->dst, name, sizeof(name), 0);
			printc("        %s%s\n",
			       e->is_tail_call ? "*" : "", name);

			j++;
		}
		printc("\n");
	}

	if (k < graph->edge_to.size &&
	    CG_EDGE_TO(graph, k)->dst == n->offset) {
		printc("    Callers:\n");
		while (k < graph->edge_to.size) {
			struct cg_edge *e = CG_EDGE_TO(graph, k);

			if (e->dst != n->offset)
				break;

			print_address(e->src, name, sizeof(name), 0);
			printc("        %s%s\n",
			       e->is_tail_call ? "*" : "", name);

			k++;
		}
	}
}