From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pf1-f172.google.com (mail-pf1-f172.google.com [209.85.210.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0253F280CE5 for ; Sat, 13 Dec 2025 03:37:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.172 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1765597032; cv=none; b=J42liPL/WMilUxOz3TGm0oes0M+yMJOXKleTltegbVaoXpm8j6TQxeoZ3sKpHcDYHHItnp7uWIQYIreScb/nZ7GsADFfb+lFXIlKNJSy2db1JtSZstgSSTT6WesrPwBr1i7nEZjmVtZpWHwP5AbCvlxHhbz+M76Nd0IwA38aG6A= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1765597032; c=relaxed/simple; bh=fqSvSrhFug2JV6WmV1UCtlSUDH6aThNUlEs/0ccCKes=; h=Message-ID:Date:MIME-Version:Subject:To:Cc:References:From: In-Reply-To:Content-Type; b=QlSHLm8kfj13uPbYDgTz1FfOYJacmEAcOPjukcSFTSZNc9rZqPOsoDg43W7puguZoo/Wfdncr/ShCYoksW/GeHCLuNWp3oyFDFvpmw2pAdzAW8mSmMKHwr6TQHmRAUGYS4eUN54sI2RD/sqL9mHh9C9vCngF8a9HNYNr2++rGrc= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Hdo0wFFi; arc=none smtp.client-ip=209.85.210.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Hdo0wFFi" Received: by mail-pf1-f172.google.com with SMTP id d2e1a72fcca58-7aae5f2633dso1955602b3a.3 for ; Fri, 12 Dec 2025 19:37:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1765597030; x=1766201830; darn=vger.kernel.org; h=content-transfer-encoding:in-reply-to:from:content-language :references:cc:to:subject:user-agent:mime-version:date:message-id :from:to:cc:subject:date:message-id:reply-to; bh=hA6QsVYx7rfhwWy/5ONDT2VzsMpUtJPGiQnqD5LqvjI=; b=Hdo0wFFiT27AAT8aMWNMysNbfkq2XLAKzIBExZtAExzlwdagRYEJA2+7YrE83qRXvN F4THCYOUiY7th2VzSobEccbdix5xNbBYh8RA+2M+wCWFSxI9Irb4Jfi8XbplvD0ng0VL MRmwev1TTGbWf4kXciMgF3zWObxxLy51roY9j4VtPU89A3L2K1+37AkjMT0h2a5yIDiN aaQzFQY4ikphTAosYy2R2f+YQKu37iD5XSszUIzmc5ecox4EyBI7H+0PCtxlR2vD8eQS x2eM1zGwCy+tNfw+PAdkvuVKO0ykVrNmqy+YNKjpZCXAu7pfmOWbvHl5Qz39/+kD1DtJ IHEA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1765597030; x=1766201830; h=content-transfer-encoding:in-reply-to:from:content-language :references:cc:to:subject:user-agent:mime-version:date:message-id :x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=hA6QsVYx7rfhwWy/5ONDT2VzsMpUtJPGiQnqD5LqvjI=; b=MAPcOCV1+NASWIK113et09bV6mY8vvRA15jgmtMBgdrXMPQHaQLZmug3FrmYiPh3i4 HVvLziaeE62H8g+3VDk9LOQNZ4+AraFOnJc7r0ScCAemvNdH2Z2JMT2nb/y0TO9dpVt/ psnf/+g7TSFHFX5ChfOqPvubtqiEDsAiMWympGug9mmIEPlH1b0FdOfNi54ANa4f3Uuk PMbeM8SMQr3eZDzDhvKcP0FhSoXlL5yeeRbdCAiC27NF2WOhvqlBOVi32/PZe0RpUoVq l0eKHLj0SY0WrzK/1BhqO/vjrbCLr/xjMmmT4vSXUFAg/o2UFzuLGRvvGaMjaBJKD/YZ rAzw== X-Forwarded-Encrypted: i=1; AJvYcCXWMt0gfKi047BEAKbJfpbKKyMiL5TrN6oQiUvXwt8oNqTiLse/rG7GG2bBTlaRP8GKA3g=@vger.kernel.org X-Gm-Message-State: AOJu0YxVDiExScBSuTpclMh42JJfSGbRQ9gvtPPCrK1PscR+jUSMYNgB XYLty3TltMBPSUiQ3shpJtkmzpq7ZUojwoR7h17SpsQyqk7XfLjOQ4Do X-Gm-Gg: AY/fxX6pRfx2WwG2fwWdZU0KiCA4cRETFhpjCxAxyxhWAkbc7Kd9JIjntH/mrXssG/k lmxhnOcBtdFPafKzdiLRoNjsrYRcMz0uCBTVnUqC2GTBpTjTaclIpcRvkEDVHoNsnzqYltst255 37Bgf1KKIihSMNhStHKVChakoTUkTlmvXuf3/h2cBgkDA6940OINe9Kmgqswb8LR2lCt/OdHaYC Yg6U7rlGFDLQD9XQmjem+XKJgzJwmBY9bJdr76VA2JW32foUokaOiyWbUdO8rwIkiyFN+q/TemY wGPz2E7PxkO91XPtScHUHpM6G8uzguDvohVMZUKWdCmjL7e1PXSjHoAQ9sEE2cRVo/Zl9sHAeE0 6k6BUWg5MjlwuFD61+LNoqoug3tlnLznWuPDdX5E1yOUyMbAPTJArWzI5KSyBE979Qf4gZDGN1v QITU8vGkxJN/qOYEO1nimcYIgYy7C+jgNYWqMGVvZ1buI/6+3L5GSiaIjn4aU= X-Google-Smtp-Source: AGHT+IEt2Ao/mpoHd/BtLxNEwCv4ALeGirUW4QnURj/7zbL6o/30qWZ9zLQvzqczttv5SSBSF3NKbw== X-Received: by 2002:a05:6a20:748a:b0:364:be7:7006 with SMTP id adf61e73a8af0-369b433b216mr4503025637.15.1765597030008; Fri, 12 Dec 2025 19:37:10 -0800 (PST) Received: from [10.200.5.118] (p99249-ipoefx.ipoe.ocn.ne.jp. [153.246.134.248]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-c0c25b7d59dsm6336281a12.6.2025.12.12.19.37.04 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 12 Dec 2025 19:37:09 -0800 (PST) Message-ID: <562aa38b-2cf0-490c-98df-0b42e1d5a599@gmail.com> Date: Sat, 13 Dec 2025 03:37:03 +0000 Precedence: bulk X-Mailing-List: bpf@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH v6 bpf-next 02/10] libbpf: Support kind layout section handling in BTF To: Alan Maguire , andrii@kernel.org, ast@kernel.org Cc: daniel@iogearbox.net, martin.lau@linux.dev, eddyz87@gmail.com, song@kernel.org, yonghong.song@linux.dev, john.fastabend@gmail.com, kpsingh@kernel.org, sdf@fomichev.me, haoluo@google.com, jolsa@kernel.org, qmo@kernel.org, ihor.solodrai@linux.dev, dwarves@vger.kernel.org, bpf@vger.kernel.org, ttreyer@meta.com References: <20251210203243.814529-1-alan.maguire@oracle.com> <20251210203243.814529-3-alan.maguire@oracle.com> Content-Language: en-US From: Mykyta Yatsenko In-Reply-To: <20251210203243.814529-3-alan.maguire@oracle.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit On 12/10/25 20:32, Alan Maguire wrote: > Support reading in kind layout fixing endian issues on reading; > also support writing kind layout section to raw BTF object. > There is not yet an API to populate the kind layout with meaningful > information. > > As part of this, we need to consider multiple valid BTF header > sizes; the original or the kind layout-extended headers. > So to support this, the "struct btf" representation is modified > to always allocate a "struct btf_header" and copy the valid > portion from the raw data to it; this means we can always safely > check fields like btf->hdr->kind_layout_len. > > Signed-off-by: Alan Maguire > --- > tools/lib/bpf/btf.c | 200 ++++++++++++++++++++++++++++++-------------- > 1 file changed, 139 insertions(+), 61 deletions(-) > > diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c > index b136572e889a..737adc560818 100644 > --- a/tools/lib/bpf/btf.c > +++ b/tools/lib/bpf/btf.c > @@ -40,42 +40,53 @@ struct btf { > > /* > * When BTF is loaded from an ELF or raw memory it is stored > - * in a contiguous memory block. The hdr, type_data, and, strs_data > + * in a contiguous memory block. The type_data, and, strs_data > * point inside that memory region to their respective parts of BTF > * representation: > * > - * +--------------------------------+ > - * | Header | Types | Strings | > - * +--------------------------------+ > - * ^ ^ ^ > - * | | | > - * hdr | | > - * types_data-+ | > - * strs_data------------+ > + * +--------------------------------+---------------------+ > + * | Header | Types | Strings |Optional kind layout | > + * +--------------------------------+---------------------+ > + * ^ ^ ^ ^ > + * | | | | > + * raw_data | | | > + * types_data-+ | | > + * strs_data------------+ | > + * kind_layout----------------------+ > + * > + * A separate struct btf_header is allocated for btf->hdr, > + * and header information is copied into it. This allows us > + * to handle header data for various header formats; the original, > + * the extended header with kind layout, etc. > * > * If BTF data is later modified, e.g., due to types added or > * removed, BTF deduplication performed, etc, this contiguous > - * representation is broken up into three independently allocated > - * memory regions to be able to modify them independently. > + * representation is broken up into four independent memory > + * regions. > + * > * raw_data is nulled out at that point, but can be later allocated > * and cached again if user calls btf__raw_data(), at which point > - * raw_data will contain a contiguous copy of header, types, and > - * strings: > + * raw_data will contain a contiguous copy of header, types, strings > + * and optionally kind_layout. kind_layout optionally points to a > + * kind_layout array - this allows us to encode information about > + * the kinds known at encoding time. If kind_layout is NULL no > + * kind information is encoded. > * > - * +----------+ +---------+ +-----------+ > - * | Header | | Types | | Strings | > - * +----------+ +---------+ +-----------+ > - * ^ ^ ^ > - * | | | > - * hdr | | > - * types_data----+ | > - * strset__data(strs_set)-----+ > + * +----------+ +---------+ +-----------+ +-----------+ > + * | Header | | Types | | Strings | |kind_layout| > + * +----------+ +---------+ +-----------+ +-----------+ > + * ^ ^ ^ ^ > + * | | | | > + * hdr | | | > + * types_data----+ | | > + * strset__data(strs_set)-----+ | > + * kind_layout--------------------------------+ > * > - * +----------+---------+-----------+ > - * | Header | Types | Strings | > - * raw_data----->+----------+---------+-----------+ > + * +----------+---------+-----------+---------------------+ > + * | Header | Types | Strings | Optional kind layout| > + * raw_data----->+----------+---------+-----------+---------------------+ > */ > - struct btf_header *hdr; > + struct btf_header *hdr; /* separately-allocated header data */ > > void *types_data; > size_t types_data_cap; /* used size stored in hdr->type_len */ > @@ -123,6 +134,13 @@ struct btf { > /* whether raw_data is a (read-only) mmap */ > bool raw_data_is_mmap; > > + /* is BTF modifiable? i.e. is it split into separate sections as described above? */ > + bool modifiable; > + /* Points either at raw kind layout data in parsed BTF (if present), or > + * at an allocated kind layout array when BTF is modifiable. > + */ > + void *kind_layout; > + > /* BTF object FD, if loaded into kernel */ > int fd; > > @@ -214,7 +232,7 @@ static int btf_add_type_idx_entry(struct btf *btf, __u32 type_off) > return 0; > } > > -static void btf_bswap_hdr(struct btf_header *h) > +static void btf_bswap_hdr(struct btf_header *h, __u32 hdr_len) > { > h->magic = bswap_16(h->magic); > h->hdr_len = bswap_32(h->hdr_len); > @@ -222,50 +240,68 @@ static void btf_bswap_hdr(struct btf_header *h) > h->type_len = bswap_32(h->type_len); > h->str_off = bswap_32(h->str_off); > h->str_len = bswap_32(h->str_len); > + /* May be operating on raw data with hdr_len that does not include below fields */ > + if (hdr_len >= sizeof(struct btf_header)) { > + h->kind_layout_off = bswap_32(h->kind_layout_off); > + h->kind_layout_len = bswap_32(h->kind_layout_len); > + } > } > > static int btf_parse_hdr(struct btf *btf) > { > - struct btf_header *hdr = btf->hdr; > + struct btf_header *hdr = btf->raw_data; > + __u32 hdr_len = hdr->hdr_len; > __u32 meta_left; > > - if (btf->raw_size < sizeof(struct btf_header)) { > + if (btf->raw_size < offsetofend(struct btf_header, str_len)) { > pr_debug("BTF header not found\n"); > return -EINVAL; > } > > if (hdr->magic == bswap_16(BTF_MAGIC)) { > btf->swapped_endian = true; > - if (bswap_32(hdr->hdr_len) != sizeof(struct btf_header)) { > + hdr_len = bswap_32(hdr->hdr_len); > + if (hdr_len < offsetofend(struct btf_header, str_len)) { > pr_warn("Can't load BTF with non-native endianness due to unsupported header length %u\n", > - bswap_32(hdr->hdr_len)); > + hdr_len); > return -ENOTSUP; > } > - btf_bswap_hdr(hdr); > } else if (hdr->magic != BTF_MAGIC) { > pr_debug("Invalid BTF magic: %x\n", hdr->magic); > return -EINVAL; > } > > - if (btf->raw_size < hdr->hdr_len) { > + if (btf->raw_size < hdr_len) { > pr_debug("BTF header len %u larger than data size %u\n", > - hdr->hdr_len, btf->raw_size); > + hdr_len, btf->raw_size); > return -EINVAL; > } > > - meta_left = btf->raw_size - hdr->hdr_len; > - if (meta_left < (long long)hdr->str_off + hdr->str_len) { > + /* At this point, we have basic header information, so allocate btf->hdr */ > + btf->hdr = calloc(1, sizeof(struct btf_header)); > + if (!btf->hdr) { > + pr_debug("BTF header allocation failed\n"); > + return -ENOMEM; > + } > + if (btf->swapped_endian) > + btf_bswap_hdr(hdr, hdr_len); > + memcpy(btf->hdr, hdr, hdr_len < sizeof(struct btf_header) ? hdr_len : > + sizeof(struct btf_header)); can we simplify this a little bit: memcpy(btf->hdr, hdr, min(hdr_len, sizeof(struct btf_header));? min macro is available in libbpf_internal.h > + > + meta_left = btf->raw_size - hdr_len; > + if (meta_left < (long long)btf->hdr->str_off + btf->hdr->str_len) { > pr_debug("Invalid BTF total size: %u\n", btf->raw_size); > return -EINVAL; > } > > - if ((long long)hdr->type_off + hdr->type_len > hdr->str_off) { > + if ((long long)btf->hdr->type_off + btf->hdr->type_len > btf->hdr->str_off) { > pr_debug("Invalid BTF data sections layout: type data at %u + %u, strings data at %u + %u\n", > - hdr->type_off, hdr->type_len, hdr->str_off, hdr->str_len); > + btf->hdr->type_off, btf->hdr->type_len, btf->hdr->str_off, > + btf->hdr->str_len); > return -EINVAL; > } > > - if (hdr->type_off % 4) { > + if (btf->hdr->type_off % 4) { > pr_debug("BTF type section is not aligned to 4 bytes\n"); > return -EINVAL; > } > @@ -292,6 +328,22 @@ static int btf_parse_str_sec(struct btf *btf) > return 0; > } > > +static int btf_parse_kind_layout_sec(struct btf *btf) > +{ > + const struct btf_header *hdr = btf->hdr; > + > + if (!hdr->kind_layout_off || !hdr->kind_layout_len) > + return 0; > + > + if (hdr->kind_layout_len % sizeof(struct btf_kind_layout) != 0) { > + pr_debug("Invalid BTF kind layout section\n"); > + return -EINVAL; > + } > + btf->kind_layout = btf->raw_data + btf->hdr->hdr_len + btf->hdr->kind_layout_off; > + > + return 0; > +} > + > static int btf_type_size(const struct btf_type *t) > { > const int base_size = sizeof(struct btf_type); > @@ -951,7 +1003,8 @@ __s32 btf__find_by_name_kind(const struct btf *btf, const char *type_name, > > static bool btf_is_modifiable(const struct btf *btf) > { > - return (void *)btf->hdr != btf->raw_data; > + /* BTF is modifiable if split into multiple sections */ > + return btf->modifiable; > } > > static void btf_free_raw_data(struct btf *btf) > @@ -980,10 +1033,11 @@ void btf__free(struct btf *btf) > * might still have a cached contiguous raw data present, > * which will be unconditionally freed below. > */ > - free(btf->hdr); > free(btf->types_data); > strset__free(btf->strs_set); > + free(btf->kind_layout); > } > + free(btf->hdr); > btf_free_raw_data(btf); > free(btf->raw_data_swapped); > free(btf->type_offs); > @@ -994,6 +1048,7 @@ void btf__free(struct btf *btf) > > static struct btf *btf_new_empty(struct btf *base_btf) > { > + struct btf_header *hdr; > struct btf *btf; > > btf = calloc(1, sizeof(*btf)); > @@ -1022,14 +1077,20 @@ static struct btf *btf_new_empty(struct btf *base_btf) > return ERR_PTR(-ENOMEM); > } > > - btf->hdr = btf->raw_data; > - btf->hdr->hdr_len = sizeof(struct btf_header); > - btf->hdr->magic = BTF_MAGIC; > - btf->hdr->version = BTF_VERSION; > + hdr = btf->raw_data; > + hdr->hdr_len = sizeof(struct btf_header); > + hdr->magic = BTF_MAGIC; > + hdr->version = BTF_VERSION; > > - btf->types_data = btf->raw_data + btf->hdr->hdr_len; > - btf->strs_data = btf->raw_data + btf->hdr->hdr_len; > - btf->hdr->str_len = base_btf ? 0 : 1; /* empty string at offset 0 */ > + btf->types_data = btf->raw_data + hdr->hdr_len; > + btf->strs_data = btf->raw_data + hdr->hdr_len; > + hdr->str_len = base_btf ? 0 : 1; /* empty string at offset 0 */ > + btf->hdr = calloc(1, sizeof(struct btf_header)); > + if (!btf->hdr) { > + free(btf); > + return ERR_PTR(-ENOMEM); > + } > + memcpy(btf->hdr, hdr, sizeof(*hdr)); > > return btf; > } > @@ -1078,7 +1139,6 @@ static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf, b > > btf->raw_size = size; > > - btf->hdr = btf->raw_data; > err = btf_parse_hdr(btf); > if (err) > goto done; > @@ -1087,6 +1147,7 @@ static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf, b > btf->types_data = btf->raw_data + btf->hdr->hdr_len + btf->hdr->type_off; > > err = btf_parse_str_sec(btf); > + err = err ?: btf_parse_kind_layout_sec(btf); > err = err ?: btf_parse_type_sec(btf); > err = err ?: btf_sanity_check(btf); > if (err) > @@ -1550,6 +1611,11 @@ static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endi > } > > data_sz = hdr->hdr_len + hdr->type_len + hdr->str_len; > + if (btf->kind_layout) { > + data_sz = roundup(data_sz, 4); > + data_sz += hdr->kind_layout_len; > + hdr->kind_layout_off = roundup(hdr->type_len + hdr->str_len, 4); > + } > data = calloc(1, data_sz); > if (!data) > return NULL; > @@ -1557,7 +1623,7 @@ static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endi > > memcpy(p, hdr, hdr->hdr_len); > if (swap_endian) > - btf_bswap_hdr(p); > + btf_bswap_hdr(p, hdr->hdr_len); > p += hdr->hdr_len; > > memcpy(p, btf->types_data, hdr->type_len); > @@ -1576,7 +1642,11 @@ static void *btf_get_raw_data(const struct btf *btf, __u32 *size, bool swap_endi > p += hdr->type_len; > > memcpy(p, btf_strs_data(btf), hdr->str_len); > - p += hdr->str_len; > + > + if (btf->kind_layout) { > + p = data + hdr->hdr_len + hdr->kind_layout_off; > + memcpy(p, btf->kind_layout, hdr->kind_layout_len); > + } > > *size = data_sz; > return data; > @@ -1717,13 +1787,13 @@ static void btf_invalidate_raw_data(struct btf *btf) > } > } > > -/* Ensure BTF is ready to be modified (by splitting into a three memory > - * regions for header, types, and strings). Also invalidate cached > - * raw_data, if any. > +/* Ensure BTF is ready to be modified (by splitting into memory regions > + * for types and strings, with kind layout section if needed (btf->hdr > + * is already a separate region). Also invalidate cached raw_data, if any. > */ > static int btf_ensure_modifiable(struct btf *btf) > { > - void *hdr, *types; > + void *types, *kind_layout = NULL; > struct strset *set = NULL; > int err = -ENOMEM; > > @@ -1733,15 +1803,20 @@ static int btf_ensure_modifiable(struct btf *btf) > return 0; > } > > - /* split raw data into three memory regions */ > - hdr = malloc(btf->hdr->hdr_len); > + /* split raw data into memory regions; btf->hdr is done already. */ > types = malloc(btf->hdr->type_len); > - if (!hdr || !types) > + if (!types) > goto err_out; > - > - memcpy(hdr, btf->hdr, btf->hdr->hdr_len); > memcpy(types, btf->types_data, btf->hdr->type_len); > > + if (btf->hdr->kind_layout_len && btf->hdr->kind_layout_off) { > + kind_layout = malloc(btf->hdr->kind_layout_len); > + if (!kind_layout) > + goto err_out; > + memcpy(kind_layout, btf->raw_data + btf->hdr->hdr_len + btf->hdr->kind_layout_off, > + btf->hdr->kind_layout_len); > + } > + > /* build lookup index for all strings */ > set = strset__new(BTF_MAX_STR_OFFSET, btf->strs_data, btf->hdr->str_len); > if (IS_ERR(set)) { > @@ -1750,11 +1825,12 @@ static int btf_ensure_modifiable(struct btf *btf) > } > > /* only when everything was successful, update internal state */ > - btf->hdr = hdr; > btf->types_data = types; > btf->types_data_cap = btf->hdr->type_len; > btf->strs_data = NULL; > btf->strs_set = set; > + if (kind_layout) > + btf->kind_layout = kind_layout; > /* if BTF was created from scratch, all strings are guaranteed to be > * unique and deduplicated > */ > @@ -1766,12 +1842,14 @@ static int btf_ensure_modifiable(struct btf *btf) > /* invalidate raw_data representation */ > btf_invalidate_raw_data(btf); > > + btf->modifiable = true; > + > return 0; > > err_out: > strset__free(set); > - free(hdr); > free(types); > + free(kind_layout); > return err; > } >