| Age | Commit message (Collapse) | Author |
|
https://git.kernel.org/pub/scm/linux/kernel/git/modules/linux.git
|
|
The type histogram maintains sample counts and periods per offset. Use
a hashmap instead of an array to reduce the memory overhead.
No functional changes intended.
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Reviewed-by: Tengda Wu <wutengda@huaweicloud.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
Enhance the x86-specific DWARF register handling by adding support for
SIMD and eGPRs registers.
This update is based on the "DWARF Register Number Mapping" table from
the "System V Application Binary Interface AMD64 Architecture Processor
Supplement" (version 1.0).
Modifications include:
- Updating the x86_64_regidx_table[] array to incorporate SIMD and eGPRs
registers.
- Enhancing the __get_dwarf_regnum_for_perf_regnum_x86_64() function to
retrieve the DWARF register index for eGPRs.
Since currently libdw doesn't support SIMD and APX eGPRs registers yet,
still keep the original return value for get_libdw_frame_nregs() helper.
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
Support dumping of SIMD registers with the new PERF_SAMPLE_REGS_ABI_SIMD
ABI.
Currently, the XMM, YMM, ZMM, OPMASK, eGPRs, and SSP registers on x86
platforms are supported with the PERF_SAMPLE_REGS_ABI_SIMD ABI.
An example of the raw format output is displayed below.
Example:
$perf record -e cycles:p -Iax,bx,r8,r16,r31,ssp,xmm,ymm,zmm,opmask ./test
$perf report -D
... ...
3342715685845 0x3afe8 [0xbc8]: PERF_RECORD_SAMPLE(IP, 0x1):
27776/27776: 0xffffffff91d7c18f period: 10000 addr: 0
... intr regs: mask 0x18001010003 ABI 64-bit SIMD
.... AX 0xffffed102de1a606
.... BX 0xffffed102de1a606
.... R8 0x0000000000000001
.... R16 0x0000000000000000
.... R31 0x0000000000000000
.... SSP 0x0000000000000000
... SIMD ABI nr_vectors 32 vector_qwords 8 nr_pred 8 pred_qwords 1
.... ZMM[0][0] 0x616c2f656d6f682f
.... ZMM[0][1] 0x696c2f7265737562
.... ZMM[0][2] 0x0000000000000000
.... ZMM[0][3] 0x0000000000000000
.... ZMM[0][4] 0x0000000000000000
.... ZMM[0][5] 0x0000000000000000
.... ZMM[0][6] 0x0000000000000000
.... ZMM[0][7] 0x0000000000000000
.... ZMM[1][0] 0x702f636578656269
.... ZMM[1][1] 0x65726f632d667265
.... ZMM[1][2] 0x0000000000000000
.... ZMM[1][3] 0x0000000000000000
.... ZMM[1][4] 0x0000000000000000
.... ZMM[1][5] 0x0000000000000000
.... ZMM[1][6] 0x0000000000000000
.... ZMM[1][7] 0x0000000000000000
... ...
.... ZMM[31][0] 0x0000000000000000
.... ZMM[31][1] 0x0000000000000000
.... ZMM[31][2] 0x0000000000000000
.... ZMM[31][3] 0x0000000000000000
.... ZMM[31][4] 0x0000000000000000
.... ZMM[31][5] 0x0000000000000000
.... ZMM[31][6] 0x0000000000000000
.... ZMM[31][7] 0x0000000000000000
.... OPMASK[0] 0x0000000000100221
.... OPMASK[1] 0x0000000000000020
.... OPMASK[2] 0x000000007fffffff
.... OPMASK[3] 0x0000000000000000
.... OPMASK[4] 0x0000000000000000
.... OPMASK[5] 0x0000000000000000
.... OPMASK[6] 0x0000000000000000
.... OPMASK[7] 0x0000000000000000
... ...
Co-developed-by: Kan Liang <kan.liang@linux.intel.com>
Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
Add support for the newly introduced SIMD register sampling format by
adding the following 5 functions:
uint64_t perf_intr_simd_reg_class_mask(uint16_t e_machine, bool pred);
uint64_t perf_user_simd_reg_class_mask(uint16_t e_machine, bool pred);
uint64_t perf_intr_simd_reg_class_bitmap_qwords(uint16_t e_machine, int reg_c,
uint16_t *qwords, bool pred);
uint64_t perf_user_simd_reg_class_bitmap_qwords(uint16_t e_machine, int reg_c,
uint16_t *qwords, bool pred);
const char *perf_simd_reg_class_name(uint16_t e_machine, int id, bool pred);
The perf_{intr|user}_simd_reg_class_mask() functions retrieve the bitmap
of kernel supported SIMD/PRED register classes on current platform for
intr-regs and user-regs sampling, such as OPMASK/XMM/YMM/ZMM on
x86 platforms.
The perf_{intr|user}_simd_reg_class_bitmap_qwords() functions retrieve
the bitmap and qwords length of a certain class of SIMD/PRED register
on current platform for intr-regs and user-regs sampling. For example,
for the XMM registers on x86 platforms, the returned bitmap is 0xffff
(XMM0 ~ XMM15) and the qwords length is 2 (128 bits for each XMM
register).
The perf_simd_reg_class_name() function gets the register class name for
a certain register class index.
Additionally, the function __parse_regs() is enhanced to support parsing
these newly introduced SIMD/PRED registers. Currently, each class of
register can only be sampled collectively; sampling a specific SIMD
register is not supported. For example, all XMM registers are sampled
together rather than sampling only XMM0.
When multiple overlapping register types, such as XMM and YMM, are
sampled simultaneously, only the superset (YMM registers) is sampled.
With this patch, all supported sampling registers on x86 platforms are
displayed as follows.
$perf record --intr-regs=?
available registers: AX BX CX DX SI DI BP SP IP FLAGS CS SS R8 R9 R10
R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28
R29 R30 R31 SSP XMM0-15 YMM0-15 ZMM0-31 OPMASK0-7
$perf record --user-regs=?
available registers: AX BX CX DX SI DI BP SP IP FLAGS CS SS R8 R9 R10
R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28
R29 R30 R31 SSP XMM0-15 YMM0-15 ZMM0-31 OPMASK0-7
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
Add support for sampling x86 extended GP registers (R16-R31) and the
shadow stack pointer (SSP) register.
The original XMM registers space in sample_regs_user/sample_regs_intr is
reclaimed to represent the eGPRs and SSP when SIMD registers sampling is
supported with the new SIMD sampling fields in the perf_event_attr
structure. This necessitates a way to distinguish which register layout
is used for the sample_regs_user/sample_regs_intr bitmap.
To address this, a new "abi" argument is added to the helpers
perf_intr_reg_mask(), perf_user_reg_mask(), and perf_reg_name(). When
"abi & PERF_SAMPLE_REGS_ABI_SIMD" is true, it indicates the eGPRs and SSP
layout is represented; otherwise, the legacy XMM registers are
represented.
Please note that PERF_SAMPLE_REGS_ABI_SIMD is set by default on platforms
that support SIMD register sampling, even when no eGPR or SSP register is
requested (for example, -Iax). As a result, sample_regs_intr and
sample_regs_usr always use the new GPR layout on platforms with SIMD
register sampling support.
The patch only supports eGPRs and SSP sampling, the complete SIMD
registers sampling would be supported in the next patch.
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
Sync the UAPI header changes of supporting SIMD/eGPRs/SSP sampling into
corresponding tools UAPI headers.
Additionally, support the new introduced perf_event_attr fields in the
perf_event_attr__fprintf and perf_event__attr_swap() helpers, and add
sanity check for the new introduced __reserved_4 field in
perf_attr_check().
Co-developed-by: Kan Liang <kan.liang@linux.intel.com>
Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
Some new introduced perf_event_attr fields, like config3 and config4,
are forgotten to add into perf_event_attr__fprintf() and
perf_event__attr_swap() helpers. Add these missed fields into these 2
helpers.
The aux_action is an exception. aux_action aliases bitfields
(e.g. aux_start_paused) in a union. Bitfields and plain u32 fields
follow different endian rules, so both views cannot be swapped
correctly at the same time. Leave aux_action unswapped until the ABI
is represented in a byte-order-safe form.
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
Tighten bounds validation in __get_dwarf_regnum_for_perf_regnum_xxx()
helpers by changing perf_regnum > ARRAY_SIZE() to
perf_regnum >= ARRAY_SIZE().
This fixes an off-by-one condition where perf_regnum == ARRAY_SIZE()
could pass validation and cause out-of-bounds access for
dwarf_xxx_regnums[].
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
Avoid a checkpatch.pl warning on the use of asm/bug.h by switching the
use of WARN macros to explicit tests and then using pr_warning from
debug.h.
Signed-off-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
strim() may advance the pointer assigned to cache->size which causes
later frees to crash.
Fix by performing the strim and then memmove-ing the potentially shifted
string back over the original string.
The bug was introduced by the transition from rtrim() to strim(), as
rtrim() wouldn't move on the left.
Fixes: 13c230ab6e56c6ae ("perf tools: Ditch rtrim(), use strim() from tools/lib")
Signed-off-by: Ian Rogers <irogers@google.com>
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
This commit updates process_compressed() to ignore comp_mmap_len == 0
when validating the compressed header. A zero size is valid and may
occur during testing.
Sashiko review flagged string.h was missing (preexisting problem) and
so I opportunistically fixed this and sorted the header files.
Signed-off-by: Ian Rogers <irogers@google.com>
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
perf report --gtk dlopen()s libperf-gtk.so, which expects to resolve
symbols back against the running perf binary (callchain_param,
symbol_conf, evsel__name, and friends live in perf, not the plugin).
Two things broke that after the GTK 4 port:
perf never passed -rdynamic, so none of its symbols were in its
dynamic symbol table for a dlopen()ed plugin to find. Add -rdynamic to
LDFLAGS when GTK4 support is enabled.
annotated_source__hist_entry() was a static inline in annotate.h, so
ui/gtk/annotate.c calling it pulled hashmap__find()'s expansion,
hashmap_find(), into libperf-gtk.so as an undefined symbol. The only
hashmap_find perf links against normally is libbpf's internal one
(tools/lib/bpf/hashmap.c), built with -fvisibility=hidden, so it can
never be exported to a dlopen()ed plugin regardless of LDFLAGS. Move
annotated_source__hist_entry() into annotate.c as an ordinary exported
function, so the plugin depends on it the same way it already depends
on evsel__group_desc() and friends.
With both fixes, a default 'make GTK4=1' build (libbpf statically
linked) can dlopen() libperf-gtk.so and open the report browser without
NO_LIBBPF=1 or manual LDFLAGS. Verified with perf report --gtk against
real perf.data on a GTK4 desktop.
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Matt Turner <mattst88@gmail.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
The helper function is_mapping_symbol() historically checks for both
local labels prefixed with ".L" or "L0" and mapping symbols prefixed
with "$".
Rename it to is_ignored_kernel_symbol() to better reflect this actual
behavior and scope, preventing conceptual confusion.
While at it, update the related non-module files, no functional changes.
Suggested-by: Petr Pavlu <petr.pavlu@suse.com>
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Reviewed-by: Huacai Chen <chenhuacai@loongson.cn>
Reviewed-by: Petr Pavlu <petr.pavlu@suse.com>
Signed-off-by: Petr Pavlu <petr.pavlu@suse.com>
|
|
Check the return value of zalloc() before dereferencing the allocated
dwfl_ui_ti structure.
Return -ENOMEM when the allocation fails to avoid a NULL pointer
dereference.
Signed-off-by: Triet Hoang <triet.hoang.dev@gmail.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
Teach perf annotate about the Alpha control-transfer instructions, so that
an Alpha perf.data gets call and jump arrows and resolved call targets,
whether it is read on Alpha or on another host.
Add tools/perf/util/annotate-arch/annotate-alpha.c with arch__new_alpha()
and an associate_instruction_ops() that classifies:
call: bsr, plus jsr and jcr as indirect calls
ret: ret
jump: br, the conditional branches beq/bne/blt/ble/bgt/bge/blbc/blbs
and fbeq/fbne/fblt/fble/fbgt/fbge, plus jmp as an indirect jump
mov: mov, fmov (objdump pseudos)
That is every mnemonic binutils can print for the branch and JSR formats.
jcr rather than jsr_coroutine, because both name the same MBR(0x1a,3)
encoding and print_insn_alpha() takes the first match in the table, where
the jcr alias has come first since the sources were imported in 1999.
bsr needs an Alpha-specific parse routine. The generic call__parse()
expects the operand string to begin with the target address, but a bsr
prints its return-address register first:
bsr t0,fffffc0001031dc0 <cserve_ena>
strtoull() then stops on the leading register name, leaving the target
address as 0, which makes call__scnprintf() fall back to printing the raw
operands and leaves target.sym unresolved so the browser cannot follow the
call. alpha_call__parse() takes the address from after the comma instead,
as s390_call__parse() does for the same reason. The PC-relative branches
need no such handling, as jump__parse() already skips up to two operands.
jsr and jmp get ins_ops that resolve no target at all. They transfer
control to a register, and their trailing operand is only a branch
prediction hint:
jsr ra,(t12),fffffc0001014ee8 <_printk>
binutils extracts that hint as a 14-bit signed field scaled by four and
prints it relative to the next instruction (extract_jhint() in alpha-opc.c,
print_insn_alpha() in alpha-dis.c), so it can name the callee only when the
callee lies within the resulting +-32KB. It also defaults to zero, which
prints as the next instruction. Of the 213750 jsr in a vmlinux built from
this tree, only 23093 hints land on a symbol; 157204 point into the middle
of an unrelated function and 33453 are that default. Parsing the hint
would therefore invent a call target for the majority of calls, so these
keep their operands, as an indirect call does elsewhere.
EM_ALPHA is 0x9026, far too large to index the e_machine-keyed
arch_new_fn[] table in arch__find(), so select arch__new_alpha explicitly
before the table lookup. Declare it in disasm.h and add the object to the
annotate-arch Build.
Disassembly itself comes from objdump/binutils, which already supports
Alpha; this provides perf's instruction-class metadata for annotation.
Tested on an EV7 Marvel, both natively and by annotating its perf.data on
an x86_64 host, over bsr to a local function, jsr through the PLT and
kernel-mode jsr; the two hosts produce identical output.
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Matt Turner <mattst88@gmail.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
When the per-thread e_machine cannot be determined from the DSOs in the
thread's maps, thread__e_machine_endian() decides between reading
/proc/<pid>/exe and falling back to the recorded session environment:
bool is_live = machine->machines == NULL;
if (!is_live) {
/* Check if the session has a data file. */
struct perf_session *session = container_of(...);
is_live = !!session->data;
}
Neither half of that works.
The back pointer added by commit a088031c4998 ("perf tools: Add machine to
machines back pointer") is set by machines__add(), which only ever adds
guests; the host machine never gets one. Host-machine threads, which is to
say almost all of them, therefore see machine->machines == NULL and are
declared live before the session is consulted at all.
The session test is also inverted. A session with a perf_data attached is
one being read from a perf.data file, i.e. exactly the case that is not
live, while a live session such as 'perf top' passes data=NULL to
__perf_session__new().
So a file-based session takes the live path and reads /proc/<pid>/exe on
the analysing host, which at best describes an unrelated process that has
since been given the recorded pid, and normally just fails, leaving
e_machine as EM_NONE. The perf_env fallback that would have supplied the
recorded architecture is never reached, and thread__e_machine() returns
EM_HOST.
For a same-architecture recording this is invisible, since EM_HOST is the
right answer anyway. Cross-architecture it is not: annotating an Alpha
perf.data on an x86_64 host selects the x86 struct arch, so the Alpha
disassembly is matched against the x86 instruction table. Alpha's 'ret'
collides with x86's and gets ret_ops, while its calls and branches match
nothing and are left unparsed, so no call target is resolved and no jump
arrows are drawn.
Set the back pointer for the host machine and correct the session test.
The new back pointer does not disturb the other reader of the field,
machine__findnew_guest_code(), which machine__resolve() only calls when
!machine__is_host(machine).
Fixes: 70351029b55677eb ("perf thread: Add support for reading the e_machine type for a thread")
Reviewed-by: Ian Rogers <irogers@google.com>
Signed-off-by: Matt Turner <mattst88@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
In get_argument_count(), the variable code_obj is assigned to itself
before being assigned the result of PyObject_GetAttrString(). This is
a redundant self-assignment that appears to be a typo.
Fix it by removing the redundant self-assignment.
Signed-off-by: Liu Jing <liujing@cmss.chinamobile.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
min_sz is set to sizeof(u64) * POWERPC_VPADTL_TYPE, but the code reads
auxtrace_info->priv[POWERPC_VPADTL_TYPE], which needs at least
POWERPC_VPADTL_TYPE + 1 elements. POWERPC_VPADTL_TYPE is the first
enumerator of the priv index enum (0), so min_sz evaluates to 0 and the
check validates only the perf_record_auxtrace_info header itself. A
PERF_RECORD_AUXTRACE_INFO event carrying a zero-length priv array then
passes the size check, and the subsequent priv[POWERPC_VPADTL_TYPE]
read runs one u64 past the validated region.
This is the same off-by-one fixed for Intel PT by commit c4362d5e1a5e
("perf intel-pt: Fix off-by-one in auxtrace_info minimum size check")
and for Intel BTS by commit b9fb8225951c ("perf intel-bts: Fix off-by-one
in auxtrace_info minimum size check").
Use sizeof(u64) * (POWERPC_VPADTL_TYPE + 1) so the highest accessed
priv index is covered by the minimum-size validation.
Fixes: c4bbd4ec2e50a9ed ("perf powerpc: Process auxtrace events and display in 'perf report -D'")
Reviewed-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Wang Yan <wangyan01@kylinos.cn>
Cc: Athira Rajeev <atrajeev@linux.ibm.com>
Cc: stable@vger.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
hist.h isn't related to UI and so remove the UI inclusion. Fix the
transitive dependency issues this exposes.
Signed-off-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
The code is mostly used by perf.c with additional unused functionality
such as function pointers derived from early git code. Moving it into
perf.c directly reduces the code footprint, drops the util/util.h
dependence from perf.c, and allows us to remove util/usage.c entirely.
The string constants are exposed in builtin.h, as they are used
in builtin-help.c.
Signed-off-by: Ian Rogers <irogers@google.com>
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
Use git clang-format to sort header files. Review header file includes
removing those that were unnecessary or adding explicit includes in
cases where transitive dependencies were be using.
Signed-off-by: Ian Rogers <irogers@google.com>
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
Move definitions to places they are used, or path.h in the case of
path.c's mkpath function. Remove unused definitions. Fix transitive
include dependencies.
Signed-off-by: Ian Rogers <irogers@google.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
To pick the first perf-tools-fixes-for-v7.3 from Namhyung.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
For an opposite-endian RAW sample, __evsel__parse_sample() passes the
input-controlled size to mem_bswap_64() before checking whether the
payload fits in the event. A truncated record can therefore make the helper
read and write past the event boundary.
A crafted perf.data file makes perf report crash with SIGSEGV. ASan
reports the out-of-bounds access. A regression test puts backed data past
the declared end and shows that it is changed before the parser returns
-EFAULT.
Move the bounds checks before mem_bswap_64(). Check the rounded length too,
because the helper accesses complete 64-bit words. Complete records are
handled as before.
Fixes: f9d8adb345d7adbb ("perf evsel: Fix swap for samples with raw data")
Reviewed-by: Ian Rogers <irogers@google.com>
Assisted-by: Symbolic
Signed-off-by: Mark Amirkan <markdamirkan@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
When perf reads an opposite-endian branch stack, __evsel__parse_sample()
swaps each entry before checking whether all entries fit in the event. A
truncated sample can therefore make the swap loop read and write past the
event boundary.
A truncated perf.data file makes perf report crash with SIGSEGV. ASan
reports an out-of-bounds read. A regression test puts an entry just past
the declared end and shows that its flags are changed before the parser
returns -EFAULT.
Move the bounds check before the byte-swap loop. Valid samples are handled
as before.
Fixes: 63c12ae2f246dcdc ("perf evsel: Add bitfield_swap() to handle branch_stack endian issue")
Reviewed-by: Ian Rogers <irogers@google.com>
Assisted-by: Symbolic
Signed-off-by: Mark Amirkan <markdamirkan@gmail.com>
Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
Add support for showing all the three possible per IP weights in
annotate. The weights are shown by defaults if any are non zero. This
is useful, especially with the new insn lat statistics, but also
for all the existing weights.
Add a hotkey to the interactive browser to turn them off (w), as well
as a perf annotate command line option.
The weights are stored unconditionally in the sym_hist_entry, which
will increase memory consumption somewhat.
Reviewed-by: Namhyung Kim <namhyung@kernel.org>
Assisted-by: omp:GPT-5.6-Luna
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
jit_repipe_code_move() allocated the mmap2 event with a hardcoded
+16, but computes event->mmap2.header.size as sizeof(event->mmap2)
minus unused filename bytes plus idr_size. When idr_size is larger
than 16, header.size exceeds the allocation, so perf_data__write()
reads past the heap allocation, leaking adjacent heap memory into the
generated perf.data file.
Size the allocation with idr_size like jit_repipe_code_load() does.
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: Opencode:DeepSeek-V4-Flash-free
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
jit_repipe_code_load() and jit_repipe_code_move() cast the sample id
area appended to the synthesized mmap2 record to a fixed:
struct {
u32 pid, tid;
u64 time;
};
and store the timestamp at offset 8 whenever PERF_SAMPLE_TIME is set.
That matches what evsel__id_hdr_size() accounts for only when
PERF_SAMPLE_TID is set as well: the fields are appended in a fixed
order, skipping the ones not requested by sample_type, so with
PERF_SAMPLE_TID unset PERF_SAMPLE_TIME starts at offset 0 and idr_size
is 8.
Storing the timestamp at offset 8 then lands 8 bytes past the end of
the id area, which for an event allocated as sizeof(*event) + idr_size
is past the end of the heap allocation, besides corrupting the record
the tooling reading it back expects.
Walk the id area in the order used by evsel__id_hdr_size(), advancing
past each field only when its sample_type bit is set, and keep the
computed timestamp in a local variable instead of reading it back from
the event buffer.
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: LLM
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
jit_repipe_code_load() only cleared the unwinding state when both
unwinding_data and eh_frame_hdr_size were set. When a record carries
unwinding data but eh_frame_hdr_size is 0, the cleanup condition fails
and the unwinding state persists in jd, being applied to all subsequent
JIT_CODE_LOAD and JIT_CODE_MOVE records, duplicating unwinding sections
in the generated ELF files and inflating their event->mmap2.len.
The record is validated upstream so eh_frame_hdr_size <= unwinding_size
always holds. Free the unwinding data based on the data pointer alone.
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: Opencode:DeepSeek-V4-Flash-free
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
debug_entry records are packed with a variable-length name[] field, so
entries after the first may start at addresses that are not naturally
aligned. jit_process_debug_info(), get_special_opcode() and
emit_lineno_info() read and write the u64 addr and int lineno fields
through struct member access, which is undefined behavior on
strict-alignment architectures.
Use get_unaligned()/put_unaligned() to read and update each field,
matching the layout the jitdump writers (LLVM, JVM agents) emit, which
packs entries without padding.
struct debug_entry.lineno is signed and emit_advance_lineno() takes a
long line delta that relies on sign extension, so the field is read
into an int: reading it into an unsigned int would turn a backward
line jump into a huge forward one and corrupt the line number program.
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: Opencode:DeepSeek-V4-Flash-free
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
debug_entry records are packed with a variable-length name[] field, so
entries after the first may start at addresses that are not naturally
aligned for their u64 addr and int lineno/discrim fields. On strict
alignment architectures the byte-swap loop in jit_get_next_entry()
performed misaligned 64-bit loads and stores through struct member
access, which is undefined behavior.
Use get_unaligned()/put_unaligned() for the byte-swap of each field.
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: Opencode:DeepSeek-V4-Flash-free
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
jit_repipe_unwinding_info() copies unwinding_size and eh_frame_hdr_size
from the jitdump record into jd-> fields without checking them against
the actual payload size. Downstream, jit_add_eh_frame_info() in
genelf.c computes unwinding_table_size = unwinding_size -
eh_frame_hdr_size, which underflows when eh_frame_hdr_size >
unwinding_size. The result is passed as d->d_size to libelf, causing
an OOB heap read into the output ELF file.
Validate that unwinding_size fits within the record payload and that
eh_frame_hdr_size does not exceed unwinding_size before allocating or
storing the values, so a bogus record cannot force a large allocation
that is then discarded.
mapped_size is likewise taken from the record and was narrowed into an
int for the mmap2 len computation in jit_repipe_code_load() and
jit_repipe_code_move(); values above INT_MAX would turn negative,
producing a wrong mmap2 length. Use uint64_t for usize so the value
cannot truncate.
Fixes: 0284fecd13b6db3e ("perf jit: Add unwinding support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Stefano Sanfilippo <ssanfilippo@chromium.org>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: LLM
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
jit_repipe_code_load() computes sym = (void *)jr + sizeof(jr->load) and
passes it to jit_emit_elf() which calls strlen(sym) via jit_write_elf().
If code_size equals total_size - sizeof(jr->load), the sym pointer
aliases the code blob with no NUL terminator, and strlen() scans past
the buffer into adjacent heap memory.
Add a memchr() check to verify the symbol name is NUL-terminated within
the region between the load header and the code blob before use.
Fixes: 598b7c6919c7bbcc ("perf jit: add source line info support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: LLM
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
The bounds-checking and nr_entry clamping added for the byte-swap path
only runs when jd->needs_bswap is true. On native-endian files, nr_entry
passes through unvalidated to jit_repipe_debug_info(), which stores it
as jd->nr_debug_entries. Downstream, jit_process_debug_info() in
genelf_debug.c iterates nr_debug_entries times via debug_entry_next(),
which calls strlen() on each entry's name field — a crafted nr_entry
causes OOB reads and writes.
Add bounds-checked iteration in jit_repipe_debug_info() that validates
each debug_entry fits in the payload and its name is NUL-terminated
before calling debug_entry_next(). Clamp nr_debug_entries to the count
of valid entries.
Fixes: 598b7c6919c7bbcc ("perf jit: add source line info support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: LLM
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
jit_open() calls dirname(jd->dir) but ignores the return value. POSIX
says dirname() may return a pointer to internal static storage — glibc
does this when the path has no '/', returning "." from a static buffer
and leaving jd->dir unchanged with the original filename.
Capture the return value and copy it back to jd->dir when dirname()
returns a different pointer.
Fixes: 9b07e27f88b9 ("perf inject: Add jitdump mmap injection support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: LLM
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
jit_repipe_code_move() allocates a perf_event with calloc but never
frees it — the 'out' label exits with only perf_sample__exit().
The sibling function jit_repipe_code_load() correctly calls
free(event) at its out label. Add the same free(event) to
jit_repipe_code_move().
Fixes: 9b07e27f88b9 ("perf inject: Add jitdump mmap injection support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: LLM
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
If the malloc() for the initial read buffer fails, jit_open() jumps to
the error label which calls funlockfile(jd->in). However, flockfile()
is called later in the function, so at this point the stream was never
locked. Calling funlockfile() on an unlocked stream is undefined
behavior per POSIX.
Split the error path into two labels: 'error' (after flockfile) calls
funlockfile before cleanup, 'error_noflock' (before flockfile) skips
the unlock.
Fixes: 9b07e27f88b9 ("perf inject: Add jitdump mmap injection support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: LLM
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
snprintf() returns the would-have-been length on truncation. When the
jitted filename exceeds PATH_MAX, the unclamped 'size' value inflates
sizeof(event->mmap2.filename) - size into a massive underflow, causing
the header.size computation to write an oversized header. The
subsequent write to 'id = event + header.size - idr_size' then corrupts
the heap.
Clamp size to PATH_MAX - 1 after snprintf in both jit_repipe_code_load()
and jit_repipe_code_move().
Fixes: 9b07e27f88b9 ("perf inject: Add jitdump mmap injection support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: LLM
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
The byte-swap loop for JIT_CODE_DEBUG_INFO uses array indexing
(jr->info.entries[n]) to iterate debug entries. struct debug_entry has
a flexible array member name[], so each entry has a different size.
Array indexing computes offsets assuming fixed-size elements, landing
inside variable-length name strings after the first entry and
byte-swapping garbage.
Additionally, nr_entry is read from untrusted jitdump input without
validation against total_size, so a crafted value causes OOB reads.
Replace the array indexing with debug_entry_next() pointer arithmetic
(which correctly accounts for the variable-length name) and
bounds-check each entry against the record's total_size before
byte-swapping.
Fixes: 9b07e27f88b9 ("perf inject: Add jitdump mmap injection support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: LLM
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
jit_repipe_debug_info() and jit_repipe_unwinding_info() compute payload
sizes by subtracting the fixed header size from total_size:
sz = jr->prefix.total_size - sizeof(jr->info);
When total_size is smaller than the header struct (from a truncated or
corrupted jitdump record), the subtraction underflows to a massive
value, causing an oversized allocation followed by an OOB memcpy.
Validate that total_size covers at least the fixed header before the
subtraction in both functions.
Fixes: 598b7c6919c7 ("perf jit: add source line info support")
Fixes: 0284fecd13b6 ("perf jit: Add unwinding support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Stefano Sanfilippo <ssanfilippo@chromium.org>
Assisted-by: LLM
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
jit_repipe_code_load() reads code_size from the jitdump record and uses
it to compute a pointer to the code blob:
code = (unsigned long)jr + jr->load.p.total_size - csize;
An oversized code_size underflows the pointer arithmetic, causing OOB
reads into earlier heap memory. Validate that code_size fits within the
record (total_size - sizeof(jr->load)) before the pointer computation.
code_size is uint64_t but csize is int; values above INT_MAX wrap
negative when narrowed into csize, which defeats the bounds check and
sends the code pointer past the end of the record. Reject those too.
Fixes: 9b07e27f88b9 ("perf inject: Add jitdump mmap injection support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: LLM
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
jit_repipe_debug_info() overwrites jd->debug_data without freeing the
previous allocation. If two consecutive JIT_CODE_DEBUG_INFO records
appear without an intervening LOAD record consuming the data, the first
allocation leaks.
The sibling jit_repipe_unwinding_info() already frees the old
jd->unwinding_data before reassignment — add the same pattern to
jit_repipe_debug_info() using zfree().
Also add cleanup of both buffers in jit_close() so they are freed when
the jitdump session ends, even if no LOAD record consumed them.
Fixes: 9b07e27f88b9 ("perf inject: Add jitdump mmap injection support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Stephane Eranian <eranian@google.com>
Assisted-by: LLM
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
jit_open() sets bsz = bs before the fread() that uses bs - bsz as the
read size, making the expression always evaluate to zero. fread() with
size 0 returns 0, which triggers the ret != 1 error path — so extended
jitdump headers (total_size > sizeof(header)) have been silently broken
since the original implementation.
Additionally, when 0 < bs <= bsz the if (bs > bsz) block is skipped
entirely, leaving extended header bytes unread in the stream. Subsequent
jit_get_next_entry() calls then parse those leftover bytes as a
jr_prefix, corrupting the record stream.
Fix by separating the buffer growth from the read: realloc only when
bs > bsz, then unconditionally fread bs bytes when bs > 0.
Fixes: 9b07e27f88b9cd78 ("perf inject: Add jitdump mmap injection support")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Assisted-by: LLM
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
|
|
In powerpc_vpadtl_sample(), raw_data of the synthetic sample points to a
struct powerpc_vpadtl_entry (48 bytes), but raw_size is set to
sizeof(record). record is a struct powerpc_vpadtl_entry pointer, so
sizeof(record) is the size of the pointer (8 bytes on 64-bit) rather
than the size of the record itself.
As a result, consumers that bound their access to raw_data by raw_size
only see or copy the first 8 bytes of each DTL entry instead of the full
record.
Use sizeof(*record) so that raw_size reflects the actual length of the
raw data.
Fixes: 8644834a482a ("perf powerpc: Process the DTL entries in queue and deliver samples")
Signed-off-by: Wang Yan <wangyan01@kylinos.cn>
Reviewed-by: Athira Rajeev <atrajeev@linux.ibm.com>
Reviewed-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
|
|
dso__load() sets the binary type of a DSO to the type of the first symbol
source found. For a DSO with a separate debug file linked via
.gnu-debuglink, that is DSO_BINARY_TYPE__DEBUGLINK, which makes
dso__get_filename() return the name of the debug file instead of the file
that was actually executed.
Consumers that need to read instruction bytes, such as Intel PT decoding
in 'perf script', then read from the debug file and produce wrong
instructions.
Prefer DSO_BINARY_TYPE__BUILD_ID_CACHE, and otherwise
DSO_BINARY_TYPE__SYSTEM_PATH_DSO, over debug-only types, which restores
the behaviour of using a file that contains the executed instructions.
This is a workaround. Properly separating the binary file used for
instructions from the file used for debug symbols is left for later.
Example:
Create a shared object with a separate .gnu_debuglink debug file. Note
that 'objcopy --only-keep-debug' leaves .text as NOBITS, so instructions
read from the debug file are zeros:
# cat > foo.c << EOF
unsigned long foo_work(unsigned long n)
{
unsigned long s = 0;
for (unsigned long i = 0; i < n; i++)
s = s * 31 + i;
return s;
}
EOF
# cat > main.c << EOF
#include <stdio.h>
unsigned long foo_work(unsigned long n);
int main(void)
{
printf("%lu\n", foo_work(1000));
return 0;
}
EOF
# gcc -g -O2 -shared -fPIC -o libfoo.so foo.c
# gcc -g -O2 -o main main.c -L. -lfoo -Wl,-rpath,'$ORIGIN'
# objcopy --only-keep-debug libfoo.so libfoo.so.debug
# objcopy --strip-debug libfoo.so
# objcopy --add-gnu-debuglink=libfoo.so.debug libfoo.so
# perf record -e intel_pt//u ./main
Note that branch samples must be requested, because it is the resolving
of the branch target symbol that causes dso__load() to be called, and
hence the binary type to be set, before the decoder walks the code.
With '--itrace=e' alone, nothing loads symbols for libfoo.so, the binary
type is left as DSO_BINARY_TYPE__NOT_FOUND, the correct file is read
anyway, and no errors are reported either way.
Before:
# perf.before script --itrace=be 2>&1 | grep "instruction trace error"
instruction trace error type 1 time 2350.467489498 cpu 9 pid 75634 tid 75634 ip 0x77d48480718f code 6: Trace doesn't match instruction
instruction trace error type 1 time 2350.467489832 cpu 9 pid 75634 tid 75634 ip 0x77d484807341 code 6: Trace doesn't match instruction
instruction trace error type 1 time 2350.467496412 cpu 9 pid 75634 tid 75634 ip 0x5b4de37a8074 code 6: Trace doesn't match instruction
instruction trace error type 1 time 2350.467593393 cpu 9 pid 75634 tid 75634 ip 0x77d4848070d0 code 6: Trace doesn't match instruction
instruction trace error type 1 time 2350.467593954 cpu 9 pid 75634 tid 75634 ip 0x77d4848075a8 code 6: Trace doesn't match instruction
instruction trace error type 1 time 2350.467595728 cpu 9 pid 75634 tid 75634 ip 0x77d4848324de code 6: Trace doesn't match instruction
6 instruction trace errors
After:
# perf script --itrace=be 2>&1 | grep "instruction trace error"
#
Fixes: 5363c306787c8 ("perf symbol: Set binary_type of dso when loading")
Reported-by: Todd Lipcon <tlipcon@google.com>
Closes: https://lore.kernel.org/all/CAGH6UiG=RJLqBU3kLu9XJciPyPO1HZkbAPERguVUMRuWQgqf=A@mail.gmail.com/
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
|
|
A common mistake when trying to record system-wide profiles for a given
duration is running commands like 'perf record sleep 1' or 'perf stat
sleep 1' without passing '-a' / '--all-cpus'. When '-a' is omitted, perf
defaults to per-process monitoring of the sleep process itself, which
does not collect system-wide activity and records very few events.
Add a warning in evlist__prepare_workload() when the workload executable
is 'sleep' and system-wide mode is not enabled.
Assisted-by: Antigravity:gemini-3.6-flash
Signed-off-by: Ian Rogers <irogers@google.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
|
|
Add the browser front end: create/run/delete the hist_browser and add the
title. The d shortcut opens the existing per-cacheline detail view for the
selected level-3 cacheline. Level-3 entries retain the source cacheline
index, so the shortcut can locate the original entry without relying on a
potentially ambiguous virtual address.
Report a warning when the common model rejects a cacheline coalescing field
list without `iaddr`. Without it, the detail histograms may already have
merged samples from different functions and cannot support reliable
function attribution.
Keep visible-row accounting local to the function view by wrapping the
generic browser refresh callback and recounting the currently reachable
hierarchy before each redraw. This keeps navigation correct when a level-1
row is collapsed while level-3 descendants remain expanded, without adding
C2C-specific hooks to the shared hist_browser. Also handle Ctrl-C like the
other function-view exit keys.
Keep callchains hidden while the function browser runs, restoring the
user's setting while opening the cacheline detail view.
Wire the builder into perf_c2c__browse_function_view().
Signed-off-by: Jiebin Sun <jiebin.sun@intel.com>
Reviewed-by: Tianyou Li <tianyou.li@intel.com>
Reviewed-by: Wangyang Guo <wangyang.guo@intel.com>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Dapeng Mi <dapeng1.mi@linux.intel.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Thomas Falcon <thomas.falcon@intel.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
|
|
Add the builder that walks the top-level cacheline entries and, for each
read-side function, correlates the functions that write the same lines
(level 2) and the specific cachelines they contend over (level 3) within
each retained detail histogram. Aggregate the write traffic per contending
function, resort by store count, and prune writers/functions with no
contention. The finalize pass then computes the Cycles % denominator from
the surviving level-1 entries after pruning, so the column shows each
function's share of the functions retained in the table rather than of the
whole recording -- the semantics documented for Cycles % in perf-c2c.txt.
Expose c2c_function__build() and c2c_function__reset() for the TUI front
end added by the next patch. The builder requires iaddr in the cacheline
coalescing fields and returns the completed hists through an output
argument. Validate the inputs before replacing an existing model.
Function-view entries do not carry callchains. Suppress callchain handling
while building and tearing down the model so the common API does not depend
on the caller's current callchain setting.
Signed-off-by: Jiebin Sun <jiebin.sun@intel.com>
Reviewed-by: Tianyou Li <tianyou.li@intel.com>
Reviewed-by: Wangyang Guo <wangyang.guo@intel.com>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Dapeng Mi <dapeng1.mi@linux.intel.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Thomas Falcon <thomas.falcon@intel.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
|
|
Add the entry-creation layer: owned-reference child allocation and
insertion, and the level-1/2/3 lookup-or-create functions keyed by
function symbol (level 1 read-side, level 2 writer) and by the source
cacheline's existing index (level 3).
Give synthetic children normal entry operations and acquire their thread
and map-symbol references. This lets the hierarchy teardown use
hist_entry__delete() for the common fields while the function-view free
callback handles the private child tree and containing allocation.
Reuse cacheline_idx to preserve the source entry identity without adding
function-view-only state. Add c2c_function__find_cacheline() to locate the
original cacheline entry by the same index.
These are driven by the hierarchy builder in the next patch and are
__maybe_unused until then.
Signed-off-by: Jiebin Sun <jiebin.sun@intel.com>
Reviewed-by: Tianyou Li <tianyou.li@intel.com>
Reviewed-by: Wangyang Guo <wangyang.guo@intel.com>
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Dapeng Mi <dapeng1.mi@linux.intel.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Thomas Falcon <thomas.falcon@intel.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
|