summaryrefslogtreecommitdiffstats
path: root/scripts/dtc/treesource.c
diff options
context:
space:
mode:
authorSteven Rostedt <rostedt@goodmis.org>2026-09-02 09:55:01 -0400
committerSteven Rostedt <rostedt@goodmis.org>2026-09-02 11:08:21 -0400
commit4617721c502b2ddaa4e324e86da4997edf738fa5 (patch)
tree350aa83b47da0b574a814795392b20b0bed83cbc /scripts/dtc/treesource.c
downloadlinux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.tar.gz
linux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.zip
ftrace: Synchronize the initialization of ftrace_opsgrafted
There's some internal state that ftrace_ops needs to have set, but since it can be declared outside of the ftrace.c code, it calls ftrace_ops_init() on the ops in every global function. The issue is that if two tasks call it on the same ops at the same time it is possible to have the initialization of one corrupt the initialization of the other call. Create a ops_mutex to use to synchronize every initialization of the ftrace_ops. The mutex is taken within checking the ftrace_ops flag that states it was initializied but the flag is checked again after the mutex has been taken. Checking first outside the mutex allows it to shortcut having to take the mutex. But then the check needs to be done again after the mute is taken in case of races. Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260902095501.6b59af20@gandalf.local.home Fixes: f04f24fb7e48d ("ftrace, kprobes: Fix a deadlock on ftrace_regex_lock") Reported-by: sashiko-bot@kernel.org Close: https://lore.kernel.org/all/20260829025528.49A831F000E9@smtp.kernel.org/ Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'scripts/dtc/treesource.c')
-rw-r--r--scripts/dtc/treesource.c437
1 files changed, 437 insertions, 0 deletions
diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c
new file mode 100644
index 000000000..bf648bf6c
--- /dev/null
+++ b/scripts/dtc/treesource.c
@@ -0,0 +1,437 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005.
+ */
+
+#include "dtc.h"
+#include "srcpos.h"
+
+extern FILE *yyin;
+extern int yyparse(void);
+extern YYLTYPE yylloc;
+
+struct dt_info *parser_output;
+bool treesource_error;
+
+struct dt_info *dt_from_source(const char *fname)
+{
+ parser_output = NULL;
+ treesource_error = false;
+
+ srcfile_push(fname);
+ yyin = current_srcfile->f;
+ yylloc.file = current_srcfile;
+
+ if (yyparse() != 0)
+ die("Unable to parse input tree\n");
+
+ if (treesource_error)
+ die("Syntax error parsing input tree\n");
+
+ return parser_output;
+}
+
+static void write_prefix(FILE *f, int level)
+{
+ int i;
+
+ for (i = 0; i < level; i++)
+ fputc('\t', f);
+}
+
+static bool isstring(char c)
+{
+ return (isprint((unsigned char)c)
+ || (c == '\0')
+ || strchr("\a\b\t\n\v\f\r", c));
+}
+
+static void write_propval_string(FILE *f, const char *s, size_t len)
+{
+ const char *end = s + len - 1;
+
+ if (!len)
+ return;
+
+ assert(*end == '\0');
+
+ fprintf(f, "\"");
+ while (s < end) {
+ char c = *s++;
+ switch (c) {
+ case '\a':
+ fprintf(f, "\\a");
+ break;
+ case '\b':
+ fprintf(f, "\\b");
+ break;
+ case '\t':
+ fprintf(f, "\\t");
+ break;
+ case '\n':
+ fprintf(f, "\\n");
+ break;
+ case '\v':
+ fprintf(f, "\\v");
+ break;
+ case '\f':
+ fprintf(f, "\\f");
+ break;
+ case '\r':
+ fprintf(f, "\\r");
+ break;
+ case '\\':
+ fprintf(f, "\\\\");
+ break;
+ case '\"':
+ fprintf(f, "\\\"");
+ break;
+ case '\0':
+ fprintf(f, "\\0");
+ break;
+ default:
+ if (isprint((unsigned char)c))
+ fprintf(f, "%c", c);
+ else
+ fprintf(f, "\\x%02"PRIx8, c);
+ }
+ }
+ fprintf(f, "\"");
+}
+
+static void write_propval_int(FILE *f, const char *p, size_t len, size_t width)
+{
+ const char *end = p + len;
+ assert(len % width == 0);
+
+ for (; p < end; p += width) {
+ switch (width) {
+ case 1:
+ fprintf(f, "%02"PRIx8, *(const uint8_t*)p);
+ break;
+ case 2:
+ fprintf(f, "0x%02"PRIx16, dtb_ld16(p));
+ break;
+ case 4:
+ fprintf(f, "0x%02"PRIx32, dtb_ld32(p));
+ break;
+ case 8:
+ fprintf(f, "0x%02"PRIx64, dtb_ld64(p));
+ break;
+ }
+ if (p + width < end)
+ fputc(' ', f);
+ }
+}
+
+static const char *delim_start[] = {
+ [TYPE_UINT8] = "[",
+ [TYPE_UINT16] = "/bits/ 16 <",
+ [TYPE_UINT32] = "<",
+ [TYPE_UINT64] = "/bits/ 64 <",
+ [TYPE_STRING] = "",
+};
+static const char *delim_end[] = {
+ [TYPE_UINT8] = "]",
+ [TYPE_UINT16] = ">",
+ [TYPE_UINT32] = ">",
+ [TYPE_UINT64] = ">",
+ [TYPE_STRING] = "",
+};
+
+/*
+ * The invariants in the marker list are:
+ * - offsets are non-strictly monotonically increasing
+ * - for a single offset there is at most one type marker
+ * - for a single offset that has both a type marker and non-type markers, the
+ * type marker appears before the others.
+ */
+static struct marker **add_marker(struct marker **mi,
+ enum markertype type, unsigned int offset, char *ref)
+{
+ struct marker *nm;
+
+ while (*mi && (*mi)->offset < offset)
+ mi = &(*mi)->next;
+
+ if (*mi && (*mi)->offset == offset && is_type_marker((*mi)->type)) {
+ if (is_type_marker(type))
+ return mi;
+ mi = &(*mi)->next;
+ }
+
+ if (*mi && (*mi)->offset == offset && type == (*mi)->type)
+ return mi;
+
+ nm = xmalloc(sizeof(*nm));
+ nm->type = type;
+ nm->offset = offset;
+ nm->ref = ref;
+ nm->next = *mi;
+ *mi = nm;
+
+ return &nm->next;
+}
+
+void property_add_marker(struct property *prop,
+ enum markertype type, unsigned int offset, char *ref)
+{
+ add_marker(&prop->val.markers, type, offset, ref);
+}
+
+static void add_string_markers(struct property *prop, unsigned int offset, int len)
+{
+ int l;
+ const char *p = prop->val.val + offset;
+ struct marker **mi = &prop->val.markers;
+
+ for (l = strlen(p) + 1; l < len; l += strlen(p + l) + 1)
+ mi = add_marker(mi, TYPE_STRING, offset + l, NULL);
+}
+
+void add_phandle_marker(struct dt_info *dti, struct property *prop, unsigned int offset)
+{
+ cell_t phandle;
+ struct node *refn;
+ char *ref;
+
+ if (prop->val.len < offset + 4) {
+ if (quiet < 1)
+ fprintf(stderr,
+ "Warning: property %s too short to contain a phandle at offset %u\n",
+ prop->name, offset);
+ return;
+ }
+
+ phandle = dtb_ld32(prop->val.val + offset);
+ refn = get_node_by_phandle(dti->dt, phandle);
+
+ if (!refn) {
+ if (quiet < 1)
+ fprintf(stderr,
+ "Warning: node referenced by phandle 0x%x in property %s not found\n",
+ phandle, prop->name);
+ return;
+ }
+
+ if (refn->labels)
+ ref = refn->labels->label;
+ else
+ ref = refn->fullpath;
+
+ add_marker(&prop->val.markers, REF_PHANDLE, offset, ref);
+}
+
+static enum markertype guess_value_type(struct property *prop, unsigned int offset, int len)
+{
+ const char *p = prop->val.val + offset;
+ int nnotstring = 0, nnul = 0;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (! isstring(p[i]))
+ nnotstring++;
+ if (p[i] == '\0')
+ nnul++;
+ }
+
+ if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= len - nnul)) {
+ if (nnul > 1)
+ add_string_markers(prop, offset, len);
+ return TYPE_STRING;
+ } else if ((len % sizeof(cell_t)) == 0) {
+ return TYPE_UINT32;
+ }
+
+ return TYPE_UINT8;
+}
+
+static void guess_type_markers(struct property *prop)
+{
+ struct marker **m = &prop->val.markers;
+ unsigned int offset = 0;
+
+ for (m = &prop->val.markers; *m; m = &((*m)->next)) {
+ if (is_type_marker((*m)->type))
+ /* assume the whole property is already marked */
+ return;
+
+ if ((*m)->offset > offset) {
+ m = add_marker(m, guess_value_type(prop, offset, (*m)->offset - offset),
+ offset, NULL);
+
+ offset = (*m)->offset;
+ }
+
+ if ((*m)->type == REF_PHANDLE) {
+ m = add_marker(m, TYPE_UINT32, offset, NULL);
+ offset += 4;
+ }
+ }
+
+ if (offset < prop->val.len)
+ add_marker(m, guess_value_type(prop, offset, prop->val.len - offset),
+ offset, NULL);
+}
+
+static void write_propval(FILE *f, struct property *prop)
+{
+ size_t len = prop->val.len;
+ struct marker *m;
+ enum markertype emit_type = TYPE_NONE;
+ char *srcstr;
+
+ if (len == 0) {
+ fprintf(f, ";");
+ if (annotate) {
+ srcstr = srcpos_string_first(prop->srcpos, annotate);
+ if (srcstr) {
+ fprintf(f, " /* %s */", srcstr);
+ free(srcstr);
+ }
+ }
+ fprintf(f, "\n");
+ return;
+ }
+
+ fprintf(f, " =");
+
+ guess_type_markers(prop);
+ m = prop->val.markers;
+
+ for_each_marker(m) {
+ size_t chunk_len = (m->next ? m->next->offset : len) - m->offset;
+ size_t data_len = type_marker_length(m) ? : len - m->offset;
+ const char *p = &prop->val.val[m->offset];
+ struct marker *m_phandle;
+
+ if (is_type_marker(m->type)) {
+ emit_type = m->type;
+ fprintf(f, " %s", delim_start[emit_type]);
+ } else if (m->type == LABEL)
+ fprintf(f, " %s:", m->ref);
+
+ if (emit_type == TYPE_NONE || chunk_len == 0)
+ continue;
+
+ switch(emit_type) {
+ case TYPE_UINT16:
+ write_propval_int(f, p, chunk_len, 2);
+ break;
+ case TYPE_UINT32:
+ m_phandle = prop->val.markers;
+ for_each_marker_of_type(m_phandle, REF_PHANDLE)
+ if (m->offset == m_phandle->offset)
+ break;
+
+ if (m_phandle) {
+ if (m_phandle->ref[0] == '/')
+ fprintf(f, "&{%s}", m_phandle->ref);
+ else
+ fprintf(f, "&%s", m_phandle->ref);
+ if (chunk_len > 4) {
+ fputc(' ', f);
+ write_propval_int(f, p + 4, chunk_len - 4, 4);
+ }
+ } else {
+ write_propval_int(f, p, chunk_len, 4);
+ }
+ if (data_len > chunk_len)
+ fputc(' ', f);
+ break;
+ case TYPE_UINT64:
+ write_propval_int(f, p, chunk_len, 8);
+ break;
+ case TYPE_STRING:
+ write_propval_string(f, p, chunk_len);
+ break;
+ default:
+ write_propval_int(f, p, chunk_len, 1);
+ }
+
+ if (chunk_len == data_len) {
+ size_t pos = m->offset + chunk_len;
+ fprintf(f, pos == len ? "%s" : "%s,",
+ delim_end[emit_type] ? : "");
+ emit_type = TYPE_NONE;
+ }
+ }
+ fprintf(f, ";");
+ if (annotate) {
+ srcstr = srcpos_string_first(prop->srcpos, annotate);
+ if (srcstr) {
+ fprintf(f, " /* %s */", srcstr);
+ free(srcstr);
+ }
+ }
+ fprintf(f, "\n");
+}
+
+static void write_tree_source_node(FILE *f, struct node *tree, int level)
+{
+ struct property *prop;
+ struct node *child;
+ struct label *l;
+ char *srcstr;
+
+ write_prefix(f, level);
+ for_each_label(tree->labels, l)
+ fprintf(f, "%s: ", l->label);
+ if (tree->name && (*tree->name))
+ fprintf(f, "%s {", tree->name);
+ else
+ fprintf(f, "/ {");
+
+ if (annotate) {
+ srcstr = srcpos_string_first(tree->srcpos, annotate);
+ if (srcstr) {
+ fprintf(f, " /* %s */", srcstr);
+ free(srcstr);
+ }
+ }
+ fprintf(f, "\n");
+
+ for_each_property(tree, prop) {
+ write_prefix(f, level+1);
+ for_each_label(prop->labels, l)
+ fprintf(f, "%s: ", l->label);
+ fprintf(f, "%s", prop->name);
+ write_propval(f, prop);
+ }
+ for_each_child(tree, child) {
+ fprintf(f, "\n");
+ write_tree_source_node(f, child, level+1);
+ }
+ write_prefix(f, level);
+ fprintf(f, "};");
+ if (annotate) {
+ srcstr = srcpos_string_last(tree->srcpos, annotate);
+ if (srcstr) {
+ fprintf(f, " /* %s */", srcstr);
+ free(srcstr);
+ }
+ }
+ fprintf(f, "\n");
+}
+
+void dt_to_source(FILE *f, struct dt_info *dti)
+{
+ struct reserve_info *re;
+
+ fprintf(f, "/dts-v1/;\n");
+ if (dti->dtsflags & DTSF_PLUGIN)
+ fprintf(f, "/plugin/;\n");
+ fprintf(f, "\n");
+
+ for (re = dti->reservelist; re; re = re->next) {
+ struct label *l;
+
+ for_each_label(re->labels, l)
+ fprintf(f, "%s: ", l->label);
+ fprintf(f, "/memreserve/\t0x%016llx 0x%016llx;\n",
+ (unsigned long long)re->address,
+ (unsigned long long)re->size);
+ }
+
+ write_tree_source_node(f, dti->dt, 0);
+}