Skip to content

Conversation

@joeyjiaojg
Copy link
Contributor

The PR is to introduce inline function decoding from debug_info info compared to previous symbols from symbol table.

Meanwhile, some fixes to fit for the inline function change.

With these changes,

  1. module name + file name can be used as the uniq id for file mapping
  2. header files and inline functions can be distinguished.

@codecov
Copy link

codecov bot commented May 18, 2022

Codecov Report

Merging #3144 (7e28df4) into master (e7f9308) will decrease coverage by 0.2%.
The diff coverage is 30.5%.

Impacted Files Coverage Δ
pkg/cover/backend/backend.go 0.0% <ø> (ø)
pkg/cover/backend/dwarf.go 0.0% <0.0%> (ø)
pkg/cover/backend/elf.go 0.0% <0.0%> (ø)
pkg/cover/report.go 77.9% <71.9%> (-3.7%) ⬇️
pkg/cover/html.go 67.0% <89.9%> (+6.9%) ⬆️
pkg/csource/csource.go 76.5% <0.0%> (-4.2%) ⬇️
prog/mutation.go 87.7% <0.0%> (-1.0%) ⬇️
prog/any.go 83.5% <0.0%> (-1.0%) ⬇️
prog/rand.go 90.6% <0.0%> (-0.8%) ⬇️
dashboard/app/main.go 72.2% <0.0%> (-0.4%) ⬇️
... and 11 more

@dvyukov
Copy link
Collaborator

dvyukov commented May 23, 2022

Hi Joey,

Please rename commit "qcom: show percent of covered pcs in funcs" to "pkg/cover: show percent of covered pcs in funcs".

@dvyukov
Copy link
Collaborator

dvyukov commented May 23, 2022

I've reviewed only the first 2 commits for now:
pkg/cover: show module in /funccover and /filecover
qcom: show percent of covered pcs in funcs

They look good to me. The other look more complex.
If you split these 2 commits into a separate PR, we can merge them sooner. It will help to make the remaining part more manageable.

@joeyjiaojg
Copy link
Contributor Author

pkg/cover: show module in /funccover and /filecover
qcom: show percent of covered pcs in funcs

Split into #3157

@tarasmadan tarasmadan self-requested a review May 23, 2022 17:02
@tarasmadan tarasmadan self-requested a review May 23, 2022 17:19
nm or llvm-nm cannot show inline function and its address, size.
However, dwarf info contains attributes for inline function.

For example:
static int do_pcm_hwsync(struct snd_pcm_substream *substream);

Function do_pcm_hwsync above has such entry in elf.
0x07adfc27:       DW_TAG_inlined_subroutine
                    DW_AT_abstract_origin       (0x07ae83cb "do_pcm_hwsync")
                    DW_AT_ranges        (0x00b68bc0
                       [0xffffffd01160b27c, 0xffffffd01160b2d4)
                       [0xffffffd01160b9ec, 0xffffffd01160ba4c)
                       [0xffffffd01160be50, 0xffffffd01160be60))
                    DW_AT_call_file     ("xxx/sound/core/pcm_native.c")
                    DW_AT_call_line     (2934)
                    DW_AT_call_column   (0x08)

So, we can use the info as address range to help coverage display.

With it, subsystem coverage is more reasonble now:
- Total PCs are align with __sanitizer_cov_trace_pc count in elf file
- Covered PCs are filtered only for the current subsystem paths.
(while previously header files like in include/linux/xx.h are also included.)
if pc < s.Start || pc > s.End {
idx--
var s *backend.Symbol
for j := idx; j < len(rg.Ranges); j++ {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function was apparently meant to be very fast (therefore there was only a binary search and a map access). With the newly introduced loop such a guarantee no longer exists.

Can you please explain why you needed the loop?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the rg.Ranges are sorted here, 1st by End address, then by start address. The idea is to let inline function appear before normal function.

	sort.Slice(allRanges, func(i, j int) bool {
		if allRanges[i].End != allRanges[j].End {
			return allRanges[i].End < allRanges[j].End
		}
		return allRanges[i].Start > allRanges[j].Start
	})

So the sort.Search only return the idx first satisfy pc >= rg.Ranges[i].Start (which might be an inline function), but we still need to continue the search from idx if the pc is inside normal function.

In average in Android kernel case, there are less than 10 inline functions for each function. So the j loop maximum will iterate 10 times, but if the pc belongs to inline function, the binary search will be enough and the j loop will only iterate once.

I didn't find any better solution than this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

	idx := sort.Search(len(rg.Ranges), func(i int) bool {
		return pc < rg.Ranges[i].Start
	})

This will find the first index when rg.Ranges[i].Start is bigger than pc (assuming that rg.Ranges are sorted by Start in an increasing order).

One point to verify -- is the precondition valid? From your sorting loop I see that it's only guaranteed that it's ordered by End. The existing code removes overlapping symbols, so if it's sorted by one end, it's also sorted by the other. But the new code, as I see, keeps everything - and therefore it's not correct to assume that we can binary-search over Start.

Maybe it makes sense to preprocess the ranges array so that it also only contains non-overlapping segments? But instead of just deleting ones that overlap you can (and should, as it seems) split big ranges into smaller ones, giving priority to those segments that are smaller. So, as a result, in findSymbol you will be able to just binary-search the segment that contains the PC and take a symbol pointer from it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to implement as you suggested, but I don't think it can overcome this problem to do binary search once.

Basically it works (split into ranges and sort) if normal function contains only one level inline functions.
However, it won't work if 1st level inline function contains 2nd level inline functions, even further level of inline functions. For this case, we still need to use binary search + linear search.

So I think sort range by End and then by Start => do binary search + limit linear search is still better. I didn't find any performance issue with this for 1 million pcs. The buildSymbol function finishes within 1 second.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will bring back the previous code and do some further opimization to limit subprograms to only those in text section in next push.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated the patch, pls check again.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is my understanding of your PR and comments, please correct me where I'm wrong.

  1. allSymbols in makeDWARFUnsafe contains both normal functions and various inlined functions.
  2. For each function, we have a number of PC ranges that belong to them.
  3. For normal functions, their ranges also include PCs that belong to functions inlined to them.
  4. Inlined functions can also have other inlined functions in them, and their PC ranges would also include PC of those inlined-inlined functions.

From the points above it follows that ranges are either completely contained within each other or don't intersect at all. De-facto there's just some kind of tree-like structure behind it.

And in findSymbol we either want to find the covering range that has the minimum width (end PC - start PC) and covers the requested PC. Or, in a tree interpretation, we want to each a leaf node.

But also the current approach to do it is fast enough. Because if you find e.g. the first End of a range that's bigger than the requested PC, then in the worst case you need to traverse all nested inline functions whose ranges end on the same End PC. Which just cannot be a too big number.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically yes, let me put more info here in case future we or someone need to revisit this.

There are some issues on current way of elf parsing:

  1. Functions are reading from .symbtab section and are assumed that the function is in continous address space. But the truth is not. I observed some functions are placed in ranges. For example asan.module_ctor below.
0000000000000000 l       .text  0000000000000000 $x.3
0000000000000638 l     F .text  0000000000000024 asan.module_ctor
000000000000065c l     F .text  0000000000000024 asan.module_dtor
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000680 l       .text  0000000000000000 $x.1
0000000000000680 l     F .text  000000000000000c asan.module_ctor
  1. No inline function info is present and so header files are assumed to have 1 total pc.
  2. Functions from .init.text or .exit.text sections are not excluded, the function start address for some symbols can be same. So during findSymbol, it might find incorrect one. (correctly me if it's already considered)

And the PR is to leverage the inline function info from dwarf records.

  1. yes for Alex's point 1, allSymbols contains both normal functions and various inlined functions. In dwarf presentation, each normal function (aka subprogram) might contain several inline functions. So for each inline function, we know which normal function it belongs, but we don't know if it's a child of another inline function easily.
  2. Yes for Alex's point 2. To avoid the relationship building of normal function and inline function, even inline function of another inline function, we use dwarf pc range (allRanges) to first sort by range.End and then range.Start, so that we can do binary search + linear search later to find which function the pc belongs to in buildSymbols.
  3. Yes for Alex's point 3. Normal functions ranges cover their inline function ranges. However, 1 pc either belongs to one normal function or one inline function. In this way, we can later do statics in /cover or /subsystemcover to say how many covered pcs in normal functions, and how many covered pcs in all functions including inline functions.
  4. Yes for Alex's point 4. In current PR implementation, wo don't need to walk inline function recursively.
  5. There might be a tree structure, but when I decoded the debuginfo, the edge info is missing at least for inline function of another inline function. Also, if there is a tree, then it's tree of DIE while not tree of ranges. So the address layout can have many senorios, for example function A range 1 + function a range 1 + function A range 2 + function a range 2 + function b range1... It seems harder to construct back to a tree.
  6. Yes, the current approach is pretty fast, 1 second for 1 million pcs in buildSymbols. So it shouldn't be a problem during findSymbol operations.
  7. Meanwhile, only functions in .text section are considered, I think it's more syzkaller friendly. Because kcov process doesn't collect any coverage from functions in .init.text and .exit.text sections.

The overall performance is not too bad, I think. The makeDWARFUnsafe only runs once which takes 1min20s, while existing way of decoding from symbtab takes ~1min if I remember correctly (on normal PC with 4 cores). For blade servers with many cores, I didn't see much impact. For refreshing /cover or /subsystemcover page, they finished in seconds.

Thanks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any further consideration?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay, I'll take one more look with a fresh mind.

Copy link
Contributor Author

@joeyjiaojg joeyjiaojg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update

@joeyjiaojg joeyjiaojg force-pushed the inlinefunc branch 3 times, most recently from c686e16 to 72e2f7a Compare May 25, 2022 09:04
@a-nogikh
Copy link
Collaborator

a-nogikh commented Jun 3, 2022

I tried to compare the upstream syzkaller vs this PR using v5.18.1 Linux (0047d57e6c91177bb731bed5ada6c211868bc27c, compiled using this config with gcc 11.2.0)

I applied this simple patch to measure time.

For the current syzkaller code:

2022/06/03 18:31:51 initializing coverage information...
2022/06/03 18:31:53 MakeReportGenerator took 2.123130372s
2022/06/03 18:31:53 128209 PCs symbolized in 214.958776ms (avg. 1.676µs)
2022/06/03 18:31:56 VMs 4, executed 23995, cover 128335, signal 182206/183516, crashes 0, repro 0
<...>
2022/06/03 18:33:58 rg.prepareFileMap took 2m4.755647766s

For this PR something went wrong.

2022/06/03 18:46:15 initializing coverage information...
2022/06/03 18:46:25 VMs 4, executed 25617, cover 127498, signal 179347/181538, crashes 0, repro 0
2022/06/03 18:46:35 VMs 4, executed 26020, cover 127977, signal 180287/182510, crashes 0, repro 0
2022/06/03 18:46:45 VMs 4, executed 26931, cover 129257, signal 182880/185004, crashes 0, repro 0
2022/06/03 18:46:55 VMs 4, executed 27737, cover 130117, signal 184399/186491, crashes 0, repro 0
2022/06/03 18:47:05 VMs 4, executed 28394, cover 130595, signal 185344/187480, crashes 0, repro 0
2022/06/03 18:47:15 VMs 4, executed 28867, cover 131216, signal 186593/188635, crashes 0, repro 0
2022/06/03 18:47:25 VMs 4, executed 29627, cover 132303, signal 188728/190766, crashes 0, repro 0
2022/06/03 18:47:35 VMs 4, executed 29938, cover 132855, signal 190436/191572, crashes 0, repro 0
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x80ed9e]

goroutine 291076 [running]:
github.com/google/syzkaller/pkg/cover/backend.readAllInlinedSubroutines(0xc00073a180, 0x9b312a?, 0xc0aeb489c0)
        /home/nogikh/syzkaller/pkg/cover/backend/dwarf.go:780 +0x23e
github.com/google/syzkaller/pkg/cover/backend.readSymbolsFromDwarf.func1.1(0x15c71b0?)
        /home/nogikh/syzkaller/pkg/cover/backend/dwarf.go:829 +0x45
created by github.com/google/syzkaller/pkg/cover/backend.readSymbolsFromDwarf.func1
        /home/nogikh/syzkaller/pkg/cover/backend/dwarf.go:828 +0x47b

@joeyjiaojg
Copy link
Contributor Author

dwarf

you are right, only tested linux kernel compiled by clang. let me check. I think gcc encodes into different gwarf info.

@joeyjiaojg
Copy link
Contributor Author

Verified gcc compiled kernel won't work, as the dwarf is encoded into different format.

DW_AT_sibling is used, and cap_task_setnice doesn't have range att

0x02ffd135:   DW_TAG_subprogram
                DW_AT_external  (true)
                DW_AT_name      ("cap_task_setnice")
                DW_AT_decl_line (1148)
                DW_AT_prototyped        (true)
                DW_AT_type      (0x02fe81c6 "int")
                DW_AT_sibling   (0x02ffd15d)
0x02ffd15d:   DW_TAG_subprogram
                DW_AT_external  (true)
                DW_AT_name      ("cap_task_setioprio")
                DW_AT_decl_line (1135)
                DW_AT_prototyped        (true)
                DW_AT_type      (0x02fe81c6 "int")
                DW_AT_inline    (DW_INL_inlined)
                DW_AT_sibling   (0x02ffd185)
0x02ffd185:   DW_TAG_subprogram
                DW_AT_external  (true)
                DW_AT_name      ("cap_task_setscheduler")
                DW_AT_decl_line (1122)
                DW_AT_prototyped        (true)
                DW_AT_type      (0x02fe81c6 "int")
                DW_AT_low_pc    (0xffffffff8067d190)
                DW_AT_high_pc   (0xffffffff8067d1a2)
                DW_AT_frame_base        (DW_OP_call_frame_cfa)
                DW_AT_GNU_all_call_sites        (true)
                DW_AT_sibling   (0x02ffd1d0)
0x02ffd1d0:   DW_TAG_subprogram
                DW_AT_name      ("cap_safe_nice")
                DW_AT_decl_line (1101)
                DW_AT_prototyped        (true)
                DW_AT_type      (0x02fe81c6 "int")
                DW_AT_low_pc    (0xffffffff8067d090)
                DW_AT_high_pc   (0xffffffff8067d181)
                DW_AT_frame_base        (DW_OP_call_frame_cfa)
                DW_AT_GNU_all_call_sites        (true)
                DW_AT_sibling   (0x02ffd52f)
0x02ffd52f:   DW_TAG_array_type
                DW_AT_type      (0x02fe8156 "char")
                DW_AT_sibling   (0x02ffd53f)
0x02ffd53f:   DW_TAG_subprogram
                DW_AT_external  (true)
                DW_AT_name      ("cap_task_fix_setuid")
                DW_AT_decl_line (1052)
                DW_AT_prototyped        (true)
                DW_AT_type      (0x02fe81c6 "int")
                DW_AT_low_pc    (0xffffffff8067cad0)
                DW_AT_high_pc   (0xffffffff8067ce8f)
                DW_AT_frame_base        (DW_OP_call_frame_cfa)
                DW_AT_GNU_all_call_sites        (true)
                DW_AT_sibling   (0x02ffdb61)

Below shows clang compiled kernel can have range info.

grep cap_task_setnice -A 10 -B 10 dwarf-vmlinux.txt

0x01f50383:       NULL

0x01f50384:     NULL

0x01f50385:   DW_TAG_subprogram
                DW_AT_low_pc    (0xffffffff80722c60)
                DW_AT_high_pc   (0xffffffff80722d19)
                DW_AT_frame_base        (DW_OP_reg7 RSP)
                DW_AT_GNU_all_call_sites        (true)
                DW_AT_name      ("cap_task_setnice")
                DW_AT_decl_line (1148)
                DW_AT_prototyped        (true)
                DW_AT_type      (0x01f3fd2b "int")
                DW_AT_external  (true)

0x01f5039f:     DW_TAG_formal_parameter
                  DW_AT_location        (0x00ac9cff:
                     [0xffffffff80722c60, 0xffffffff80722c6d): DW_OP_reg5 RDI
                     [0xffffffff80722c6d, 0xffffffff80722c91): DW_OP_reg3 RBX

@a-nogikh
Copy link
Collaborator

a-nogikh commented Jun 8, 2022

Syzkaller should definitely be able to adequately handle both gcc- and clang- compiled kernels.

@joeyjiaojg
Copy link
Contributor Author

Syzkaller should definitely be able to adequately handle both gcc- and clang- compiled kernels.

Right, I'm recoding some of the logic, it works for both gcc and clang now, but still need some tests before pushing.

Performance testing result for upstream linux compiled by clang:

    2022/06/08 11:21:33 initializing coverage information...
    2022/06/08 11:22:08 readSymbolsFromDwarf took 33.243243324s for 536142 functions
    2022/06/08 11:22:10 buildSymbols for 2221532 coverPoints, 525856 ranges
    2022/06/08 11:22:10 buildSymbols took 383.339292ms
@joeyjiaojg
Copy link
Contributor Author

@a-nogikh pushed the new code, please review again

Tested on linux master with both gcc-9, gcc-11, clang-14.

@a-nogikh
Copy link
Collaborator

Hi Joey,

Yes, now I was able to run it. It's a bit slower (by ~15%, it seems, but I did not do many runs), which is not a big deal. The generated HTML file was also somewhat different.

And it's about the expected difference in behavior that I now want to ask you (yeah, that should have been my first question here, but better later than never :) ).

  1. What was your specific problem you were trying to solve with this PR?
  2. What difference should a person that explores the HTML coverage report notice? It would be great if you gave some specific examples.

Some examples that seemed a bit confusing to me.

  1. Different sets of non-covered coverage points (red)

Upstream syzkaller:
image
Syzkaller from your PR:
image

What made that possible?

  1. Different sets of covered coverage points (black)

Upstream:
image

Your PR:
image

Right now syzkaller anyway extracts the specific affected lines via addr2line, and that tool also shows to which inlined functions belongs each PC we ask it about. So, which changes in this PR made for the difference between these two screenshots?

@joeyjiaojg
Copy link
Contributor Author

@a-nogikh

  • What was your specific problem you were trying to solve with this PR?
  1. The PR is mainly to solve PCs inside inline function and header files are not separated during /subsystemcover shown. So, header files and/or inline functions in header files can be used by multiple c files. If the header file is shared among different subsystems, we might not be care about coverage rate insider header files.
  2. And it also fixes confusing part of during coverage shown and pcs not selected into correct symbols in some corner cases in current buildSymbols.
  • What difference should a person that explores the HTML coverage report notice? It would be great if you gave some specific examples.
    The coverage shown difference is mainly caused by the change below. I think we shouldn't filter out other frames with the same PC.
-       uniqueFrames := make(map[uint64]bool)
-       var finalFrames []backend.Frame
-       for _, frame := range rg.Frames {
-               if !uniqueFrames[frame.PC] {
-                       uniqueFrames[frame.PC] = true
-                       finalFrames = append(finalFrames, frame)
-               }
-       }
-       rg.Frames = finalFrames
+       sort.Slice(rg.Frames, func(i, j int) bool {
+               return rg.Frames[i].PC < rg.Frames[j].PC
+       })

We know when addr2line decodes one PC which has multiple frames, we should show these multiple frames to explictly show that the function is hit too. The reason behind is for the inline function, it can have multiple callers, and multiple repensentation in dwarf section with different ranges.
For example, inline function A is called by two normal functions B and C, and so A at least have range r[start1, end1] and r[start2, end2]. When one PC is decoded, it shows A is hitted in current syzkaller, but we don't know which normal function is called. By applying below fix, then we know it can be from B or C.
I think it's more reasonable now for developer to understand more similiar way as gcov or lcov style.

For Some examples that seemed a bit confusing to me.
Let me try to explain.
By looking at below dwarf extraction, we know audit_log_start is a normal function, if any pc inside it is hit, it means the function is hit too. The current syzkaller cover page shows L1591 is hit, but we don't know if audit_log_start is hit and so we have to search the function to check. But with the PR, we don't need to do so. It's the same case for current_cred function.

0x0129b33f: DW_TAG_subprogram
              DW_AT_low_pc      (0xffffffff817fc940)
              DW_AT_high_pc     (0xffffffff817fcd0b)
              DW_AT_frame_base  (DW_OP_reg6 RBP)
              DW_AT_call_all_calls      (true)
              DW_AT_name        ("audit_log_multicast")
              DW_AT_decl_file   ("/local/mnt/workspace/xx/linux/kernel/audit.c")
              DW_AT_decl_line   (1584)
              DW_AT_prototyped  (true)

0x0129ce93: DW_TAG_subprogram
              DW_AT_low_pc      (0xffffffff817f3320)
              DW_AT_high_pc     (0xffffffff817f3ce5)
              DW_AT_frame_base  (DW_OP_reg6 RBP)
              DW_AT_call_all_calls      (true)
              DW_AT_name        ("audit_log_start")
              DW_AT_decl_file   ("/local/mnt/workspace/xx/linux/kernel/audit.c")
              DW_AT_decl_line   (1846)
              DW_AT_prototyped  (true)
              DW_AT_type        (0x0129cd57 "audit_buffer *")
              DW_AT_external    (true)

0x012b813a: DW_TAG_subprogram
              DW_AT_name        ("audit_log_start")
              DW_AT_decl_file   ("/local/mnt/workspace/xx/linux/./include/linux/audit.h")
              DW_AT_decl_line   (162)
              DW_AT_prototyped  (true)
              DW_AT_type        (0x012b8153 "audit_buffer *")
              DW_AT_declaration (true)
              DW_AT_external    (true)

For audit_log_format, the same case for L1600. It's more reasonable to say there is a PC can be reachable from L1600.

0x0129d319: DW_TAG_subprogram
              DW_AT_low_pc      (0xffffffff817f3cf0)
              DW_AT_high_pc     (0xffffffff817f3e00)
              DW_AT_frame_base  (DW_OP_reg6 RBP)
              DW_AT_call_all_calls      (true)
              DW_AT_name        ("audit_log_format")
              DW_AT_decl_file   ("/local/mnt/workspace/jiangenj/linux/kernel/audit.c")
              DW_AT_decl_line   (1992)
              DW_AT_prototyped  (true)
              DW_AT_external    (true)

0xffffffff8176f315
get_current
arch/x86/include/asm/current.h:15 (discriminator 2)
audit_log_multicast
kernel/audit.c:1600 (discriminator 2)

Different sets of covered coverage points (black)
You can see there is a PC at ffffffff8176c4e2. It should be colored not matter if it's hit.

0x022ba17a: DW_TAG_inlined_subroutine
              DW_AT_abstract_origin     (0x022b82b3 "audit_ctl_owner_current")
              DW_AT_entry_pc    (0xffffffff8176c4e2)
              DW_AT_GNU_entry_view      (0x0000)
              DW_AT_low_pc      (0xffffffff8176c4e2)
              DW_AT_high_pc     (0xffffffff8176c4e7)
              DW_AT_call_file   ("/local/mnt/workspace/xx/linux.gcc/kernel/audit.c")
              DW_AT_call_line   (1868)
              DW_AT_call_column (0x25)
              DW_AT_sibling     (0x022ba21a)

ffffffff8176c4dc:       0f 85 98 01 00 00       jne    ffffffff8176c67a <audit_log_start.part.0+0x24a>
ffffffff8176c4e2:       e8 99 18 03 00          callq  ffffffff8179dd80 <__sanitizer_cov_trace_pc>
ffffffff8176c4e7:       48 39 2d 02 33 e7 0e    cmp    %rbp,0xee73302(%rip)        # ffffffff905df7f0 <audit_cmd_mutex+0x90>
ffffffff8176c4ee:       0f 84 86 01 00 00       je     ffffffff8176c67a <audit_log_start.part.0+0x24a>

Hope it answers all the doubts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants