cov/
raw.rs

1//! The raw structures of a GCNO/GCDA file.
2
3use error::*;
4use intern::{Interner, Symbol};
5#[cfg(feature = "serde")]
6use intern::SerializeWithInterner;
7use reader::Reader;
8
9use byteorder::{BigEndian, ByteOrder};
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Deserializer, Serialize, Serializer};
12
13use std::{fmt, u64};
14use std::collections::BTreeMap;
15use std::fs::File;
16use std::io::BufReader;
17use std::path::{Path, PathBuf};
18#[cfg(feature = "serde")]
19use std::result::Result as StdResult;
20use std::str::FromStr;
21
22//----------------------------------------------------------------------------------------------------------------------
23//{{{ Gcov & RecordIndex
24
25derive_serialize_with_interner! {
26    /// The GCNO/GCDA file content.
27    #[derive(Clone, PartialEq, Eq, Hash, Debug)]
28    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
29    pub struct Gcov {
30        /// File type.
31        pub ty: Type,
32        /// File version.
33        pub version: Version,
34        /// The stamp value uniquely identifies a GCNO between consecutive compilations. The corresponding GCDA will
35        /// have the same stamp.
36        pub stamp: u32,
37        /// Vector of records.
38        pub records: Vec<Record>,
39        /// Source of the gcov file
40        #[serde(skip)]
41        pub src: Option<PathBuf>,
42    }
43}
44
45impl Gcov {
46    /// Parses the file with at the given path as GCNO/GCDA format.
47    ///
48    /// # Errors
49    ///
50    /// * Returns [`UnknownFileType`] if the file is not a in GCNO/GCDA format.
51    /// * Returns [`UnsupportedVersion`] if the GCNO/GCDA version is not supported by this crate.
52    /// * Returns [`UnknownTag`] if the GCNO/GCDA contains an unrecognized record tag.
53    /// * Returns [`Io`] on I/O failure.
54    ///
55    /// [`UnknownFileType`]: ../error/enum.ErrorKind.html#variant.UnknownFileType
56    /// [`UnsupportedVersion`]: ../error/enum.ErrorKind.html#variant.UnsupportedVersion
57    /// [`UnknownTag`]: ../error/enum.ErrorKind.html#variant.UnknownTag
58    /// [`Io`]: ../error/enum.ErrorKind.html#variant.Io
59    pub fn open<P: AsRef<Path>>(p: P, interner: &mut Interner) -> Result<Gcov> {
60        debug!("open gcov file {:?}", p.as_ref());
61        let src = p.as_ref().to_owned();
62        Location::File(src.clone()).wrap(|| -> Result<Gcov> {
63            let reader = BufReader::new(File::open(p)?);
64            let mut gcov = Reader::new(reader, interner)?.parse()?;
65            gcov.src = Some(src);
66            Ok(gcov)
67        })
68    }
69}
70
71//}}}
72//----------------------------------------------------------------------------------------------------------------------
73//{{{ Type
74
75/// File type.
76#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
77#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
78pub enum Type {
79    /// The GCNO (**gc**ov **no**tes) file, with file extension `*.gcno`.
80    Gcno,
81    /// The GCDA (**gc**ov **da**ta) file, with file extension `*.gcda`.
82    Gcda,
83}
84
85impl fmt::Display for Type {
86    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
87        fmt.write_str(match *self {
88            Type::Gcno => "gcno",
89            Type::Gcda => "gcda",
90        })
91    }
92}
93
94//}}}
95//----------------------------------------------------------------------------------------------------------------------
96//{{{ Tag
97
98/// Tag of a record.
99#[derive(Copy, Clone, PartialEq, Eq, Hash)]
100#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
101pub struct Tag(pub u32);
102
103/// The tag for the end of file.
104pub const EOF_TAG: Tag = Tag(0);
105/// The tag for an [`ANNOUNCE_FUNCTION` record](./struct.Function.html).
106pub const FUNCTION_TAG: Tag = Tag(0x01_00_00_00);
107/// The tag for a [`BASIC_BLOCK` record](./struct.Blocks.html).
108pub const BLOCKS_TAG: Tag = Tag(0x01_41_00_00);
109/// The tag for an [`ARCS` record](./struct.Arcs.html).
110pub const ARCS_TAG: Tag = Tag(0x01_43_00_00);
111/// The tag for a [`LINES` record](./struct.Lines.html).
112pub const LINES_TAG: Tag = Tag(0x01_45_00_00);
113/// The tag for a [`COUNTS` record](./struct.ArcCounts.html).
114pub const COUNTER_BASE_TAG: Tag = Tag(0x01_a1_00_00);
115/// The tag for a [`SUMMARY` record](./struct.Summary.html).
116pub const OBJECT_SUMMARY_TAG: Tag = Tag(0xa1_00_00_00);
117/// The tag for a program-`SUMMARY` record, which has been deprecated and is always skipped when present.
118pub const PROGRAM_SUMMARY_TAG: Tag = Tag(0xa3_00_00_00);
119/// Tag of record used by AutoFDO.
120pub const AFDO_FILE_NAMES_TAG: Tag = Tag(0xaa_00_00_00);
121/// Tag of record used by AutoFDO.
122pub const AFDO_FUNCTION_TAG: Tag = Tag(0xac_00_00_00);
123/// Tag of record used by AutoFDO.
124pub const AFDO_WORKING_SET_TAG: Tag = Tag(0xaf_00_00_00);
125
126impl fmt::Display for Tag {
127    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
128        write!(fmt, "0x{:08x}", self.0)
129    }
130}
131
132impl fmt::Debug for Tag {
133    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
134        write!(fmt, "Tag(0x{:08x})", self.0)
135    }
136}
137
138impl fmt::LowerHex for Tag {
139    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
140        self.0.fmt(fmt)
141    }
142}
143
144impl fmt::UpperHex for Tag {
145    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
146        self.0.fmt(fmt)
147    }
148}
149
150//}}}
151//----------------------------------------------------------------------------------------------------------------------
152//{{{ Version
153
154/// File version.
155#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
156pub struct Version(u32);
157
158/// An invalid file version.
159pub const INVALID_VERSION: Version = Version(0);
160
161/// GCNO/GCDA version targeting gcc 4.7.
162///
163/// Starting from this version the gcov format is modified in an incompatible way.
164pub const VERSION_4_7: Version = Version(0x34_30_37_2a);
165
166impl Version {
167    /// Converts a raw version number to a `Version` structure.
168    ///
169    /// # Errors
170    ///
171    /// Returns [`UnsupportedVersion`] if the version is not supported by this crate.
172    ///
173    /// [`UnsupportedVersion`]: ../error/enum.ErrorKind.html#variant.UnsupportedVersion
174    pub fn try_from(raw_version: u32) -> Result<Version> {
175        ensure!(raw_version & 0x80_80_80_ff == 0x2a, ErrorKind::UnsupportedVersion(raw_version));
176        Ok(Version(raw_version))
177    }
178}
179
180
181impl fmt::Debug for Version {
182    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
183        write!(fmt, "Tag(\"{}\")", self)
184    }
185}
186
187impl fmt::Display for Version {
188    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
189        use std::fmt::Write;
190        fmt.write_char((self.0 >> 24 & 0xff) as u8 as char)?;
191        fmt.write_char((self.0 >> 16 & 0xff) as u8 as char)?;
192        fmt.write_char((self.0 >> 8 & 0xff) as u8 as char)?;
193        fmt.write_char((self.0 & 0xff) as u8 as char)?;
194        Ok(())
195    }
196}
197
198impl FromStr for Version {
199    type Err = Error;
200    fn from_str(s: &str) -> Result<Self> {
201        ensure!(s.len() == 4, ErrorKind::UnsupportedVersion(0));
202        let raw_version = BigEndian::read_u32(s.as_bytes());
203        Version::try_from(raw_version)
204    }
205}
206
207#[cfg(feature = "serde")]
208impl Serialize for Version {
209    fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
210        serializer.collect_str(self)
211    }
212}
213
214#[cfg(feature = "serde")]
215impl<'de> Deserialize<'de> for Version {
216    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
217        use serde::de::Error;
218        let s = <&'de str>::deserialize(deserializer)?;
219        Version::from_str(s).map_err(D::Error::custom)
220    }
221}
222
223//}}}
224//----------------------------------------------------------------------------------------------------------------------
225//{{{ Record
226
227/// A record in a gcov file.
228#[derive(Clone, PartialEq, Eq, Hash, Debug)]
229#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
230pub enum Record {
231    /// An `ANNOUNCE_FUNCTION` record in GCNO and GCDA formats.
232    Function(Ident, Function),
233    /// A `BASIC_BLOCK` record in GCNO format.
234    Blocks(Blocks),
235    /// An `ARCS` record in GCNO format.
236    Arcs(Arcs),
237    /// A `LINES` record in GCNO format.
238    Lines(Lines),
239    /// A `COUNTS` record in GCDA format.
240    ArcCounts(ArcCounts),
241    /// A `SUMMARY` record in GCDA format.
242    Summary(Summary),
243}
244
245#[cfg(feature = "serde")]
246impl SerializeWithInterner for Record {
247    fn serialize_with_interner<S: Serializer>(&self, serializer: S, interner: &Interner) -> StdResult<S::Ok, S::Error> {
248        match *self {
249            Record::Function(ref ident, ref function) => {
250                use serde::ser::SerializeTupleVariant;
251                let mut state = serializer.serialize_tuple_variant("Record", 0, "Function", 2)?;
252                state.serialize_field(ident)?;
253                state.serialize_field(&function.with_interner(interner))?;
254                state.end()
255            },
256            Record::Lines(ref lines) => serializer.serialize_newtype_variant("Record", 3, "Lines", &lines.with_interner(interner)),
257            _ => self.serialize(serializer),
258        }
259    }
260}
261
262//}}}
263//----------------------------------------------------------------------------------------------------------------------
264//{{{ Function, Ident & Source
265
266derive_serialize_with_interner! {
267    /// Information of a function.
268    #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
269    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
270    pub struct Function {
271        /// The line-number checksum of this function.
272        pub lineno_checksum: u32,
273        /// The configuration checksum of this function. On versions before 4.7, this value is always 0.
274        pub cfg_checksum: u32,
275        /// The source location of this function. This field is `None` in a GCDA.
276        #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
277        pub source: Option<Source>,
278    }
279}
280
281/// Function identifier. The identifier is used to match between two `ANNOUNCE_FUNCTION` records between the GCNO and
282/// GCDA. The identifier is not necessarily sequential.
283#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
284#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
285pub struct Ident(pub u32);
286
287impl fmt::Debug for Ident {
288    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
289        write!(fmt, "Ident({})", self.0)
290    }
291}
292
293impl fmt::Display for Ident {
294    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
295        self.0.fmt(fmt)
296    }
297}
298
299derive_serialize_with_interner! {
300    /// Source location of a function.
301    #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
302    #[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
303    pub struct Source {
304        /// Function name
305        pub name: Symbol,
306        /// File name
307        pub filename: Symbol,
308        /// Line number
309        pub line: u32,
310    }
311}
312
313//}}}
314//----------------------------------------------------------------------------------------------------------------------
315//{{{ Blocks
316
317macro_rules! derive_serde_for_attr {
318    ($flags:path, $kind:expr, $allowed_from_gcno:expr) => {
319        #[cfg(feature="serde")]
320        impl Serialize for $flags {
321            fn serialize<S: Serializer>(&self, serializer: S) -> StdResult<S::Ok, S::Error> {
322                serializer.serialize_u16(self.bits())
323            }
324        }
325
326        #[cfg(feature="serde")]
327        impl<'de> Deserialize<'de> for $flags {
328            fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
329                use ::serde::de::Error;
330                let b = u16::deserialize(deserializer)?;
331                <$flags>::from_bits(b).ok_or_else(|| D::Error::custom(ErrorKind::UnsupportedAttr($kind, b as u32)))
332            }
333        }
334
335        impl $flags {
336            /// Converts an integer read from GCNO to this attribute.
337            ///
338            /// # Errors
339            ///
340            /// Returns [`UnsupportedAttr`] if the GCNO flag is unrecognized.
341            ///
342            /// [`UnsupportedAttr`]: ../error/enum.ErrorKind.html#variant.UnsupportedAttr
343            pub fn from_gcno(flags: u32) -> Result<$flags> {
344                ensure!(flags & !($allowed_from_gcno.bits() as u32) == 0, ErrorKind::UnsupportedAttr($kind, flags));
345                Ok(<$flags>::from_bits_truncate(flags as u16))
346            }
347        }
348    }
349}
350
351/// List of [basic blocks](https://en.wikipedia.org/wiki/Basic_block).
352#[derive(Clone, PartialEq, Eq, Hash, Debug)]
353#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
354pub struct Blocks {
355    /// The attributes for each block, in sequence.
356    pub flags: Vec<BlockAttr>,
357}
358
359bitflags! {
360    /// Attributes about a [basic block](https://en.wikipedia.org/wiki/Basic_block).
361    #[derive(Default)]
362    pub struct BlockAttr: u16 {
363        /// The block is unexpected.
364        ///
365        /// Equivalent to the `GCOV_BLOCK_UNEXPECTED` flag.
366        const UNEXPECTED = 2;
367
368        /// The block ends with a function call which may throw an exception.
369        const CALL_SITE = 0x1000;
370
371        /// The block starts with the return from a function call.
372        const CALL_RETURN = 0x2000;
373
374        /// The block is the landing pad for `longjmp`.
375        const NONLOCAL_RETURN = 0x4000;
376
377        /// The block starts as a catch block.
378        const EXCEPTIONAL = 0x8000;
379    }
380}
381
382derive_serde_for_attr! {
383    BlockAttr, "block", BlockAttr::UNEXPECTED
384}
385
386/// Index to a block the [`Blocks`].
387///
388/// [`Blocks`]: ./struct.Blocks.html
389#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
390#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
391pub struct BlockIndex(pub u32);
392
393impl fmt::Debug for BlockIndex {
394    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
395        write!(fmt, "BI({})", self.0)
396    }
397}
398
399impl From<BlockIndex> for usize {
400    fn from(i: BlockIndex) -> usize {
401        i.0 as usize
402    }
403}
404
405//}}}
406//----------------------------------------------------------------------------------------------------------------------
407//{{{ Arcs
408
409/// List of arcs (out-going edges) from a single basic block.
410#[derive(Clone, PartialEq, Eq, Hash, Debug)]
411#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
412pub struct Arcs {
413    /// The predecessor basic block of this collection of arcs.
414    pub src_block: BlockIndex,
415    /// The arcs going out from the `src_block`.
416    pub arcs: Vec<Arc>,
417}
418
419bitflags! {
420    /// Attributes about an [`Arc`].
421    ///
422    /// [`Arc`]: ./struct.Arc.html
423    #[derive(Default)]
424    pub struct ArcAttr: u16 {
425        /// The arc is a non-instrumentable edge on the spanning tree. This arc will not appear in the corresponding
426        /// GCDA file.
427        ///
428        /// Equivalent to the `GCOV_ARC_ON_TREE` flag.
429        const ON_TREE = 1;
430
431        /// The arc is fake. Such arcs connect no-return blocks (e.g. infinite loop and `-> !` functions) to the exit
432        /// block, i.e. in reality this arc should never be taken.
433        ///
434        /// Equivalent to the `GCOV_ARC_FAKE` flag.
435        const FAKE = 2;
436
437        /// The arc is fall-through.
438        ///
439        /// Equivalent to the `GCOV_ARC_FALLTHROUGH` flag.
440        const FALLTHROUGH = 4;
441
442        /// The arc is taken to a `catch` handler.
443        const THROW = 0x10;
444
445        /// The arc is for a function that abnormally returns.
446        const CALL_NON_RETURN = 0x20;
447
448        /// The arc is for `setjmp`.
449        const NONLOCAL_RETURN = 0x40;
450
451        /// The arc is an unconditional branch.
452        const UNCONDITIONAL = 0x80;
453    }
454}
455
456derive_serde_for_attr! {
457    ArcAttr, "arc", ArcAttr::ON_TREE | ArcAttr::FAKE | ArcAttr::FALLTHROUGH
458}
459
460/// An arc.
461#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
462#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
463pub struct Arc {
464    /// The destination basic block of the arc. The source is in the [`Arcs`] structure.
465    ///
466    /// [`Arcs`]: ./struct.Arcs.html
467    pub dest_block: BlockIndex,
468
469    /// The attribute of this arc.
470    pub flags: ArcAttr,
471}
472
473//}}}
474//----------------------------------------------------------------------------------------------------------------------
475//{{{ Lines
476
477derive_serialize_with_interner! {
478    /// Information about source lines covered by a basic block.
479    #[derive(Clone, PartialEq, Eq, Hash, Debug)]
480    #[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
481    pub struct Lines {
482        /// The basic block which contains these source information.
483        pub block_number: BlockIndex,
484        /// The line numebers. The vector typically starts with a [`FileName`], followed by many [`LineNumber`]s.
485        ///
486        /// [`FileName`]: ./enum.Line.html#variant.FileName
487        /// [`LineNumber`]: ./enum.Line.html#variant.LineNumber
488        pub lines: Vec<Line>,
489    }
490}
491
492/// A source line entry of a basic block.
493#[derive(Copy, Clone, PartialEq, Eq, Hash)]
494#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
495#[cfg_attr(feature = "serde", serde(untagged))]
496pub enum Line {
497    /// A line number inside the basic block.
498    LineNumber(u32),
499    /// The file name containing the basic block.
500    FileName(Symbol),
501}
502
503impl fmt::Debug for Line {
504    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
505        match *self {
506            Line::LineNumber(ref n) => write!(fmt, "Line({:?})", n),
507            Line::FileName(ref n) => write!(fmt, "Line({:?})", n),
508        }
509    }
510}
511
512#[cfg(feature = "serde")]
513impl SerializeWithInterner for Line {
514    fn serialize_with_interner<S: Serializer>(&self, serializer: S, interner: &Interner) -> StdResult<S::Ok, S::Error> {
515        match *self {
516            Line::LineNumber(number) => number.serialize(serializer),
517            Line::FileName(symbol) => symbol.serialize_with_interner(serializer, interner),
518        }
519    }
520}
521
522//}}}
523//----------------------------------------------------------------------------------------------------------------------
524//{{{ ArcCounts
525
526/// Counter of how many times an arc is taken. Only arcs without the [`ArcAttr::ON_TREE`] flag will be recorded.
527///
528/// [`ArcAttr::ON_TREE`]: ./constant.ArcAttr::ON_TREE.html
529#[derive(Clone, PartialEq, Eq, Hash, Debug)]
530#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
531pub struct ArcCounts {
532    /// How many times an arc is taken. The vector lists the counts for each arc.
533    pub counts: Vec<u64>,
534}
535
536//}}}
537//----------------------------------------------------------------------------------------------------------------------
538//{{{ Summary & Histogram
539
540/// Object summary.
541#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
542#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
543pub struct Summary {
544    /// Checksum of the object.
545    pub checksum: u32,
546    /// Number of counters.
547    pub num: u32,
548    /// Number of program runs.
549    pub runs: u32,
550    /// Sum of all counters accumulated.
551    pub sum: u64,
552    /// Maximum count of a single run.
553    pub max: u64,
554    /// Sum of individual maximum counts.
555    pub sum_max: u64,
556    /// Histogram of counter values.
557    pub histogram: Option<Histogram>,
558}
559
560/// Histogram in the [`Summary`].
561///
562/// [`Summary`]: ./struct.Summary.html
563#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
564#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
565pub struct Histogram {
566    /// Buckets in the histogram.
567    ///
568    /// The key gives the scale-index.
569    pub buckets: BTreeMap<u32, HistogramBucket>,
570}
571
572/// A bucket in the [`Histogram`].
573///
574/// [`Histogram`]: ./struct.Histogram.html
575#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
576#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
577pub struct HistogramBucket {
578    /// Number of counters whose profile count falls within the bucket.
579    pub num: u32,
580    /// Smallest profile count included in this bucket.
581    pub min: u64,
582    /// Cumulative value of the profile counts in this bucket.
583    pub sum: u64,
584}
585
586impl Default for HistogramBucket {
587    fn default() -> HistogramBucket {
588        HistogramBucket {
589            num: 0,
590            min: u64::MAX,
591            sum: 0,
592        }
593    }
594}
595
596//}}}
597
598derive_serialize_with_interner! {
599    direct: Type, Tag, Version, Ident, BlockAttr, ArcAttr, Blocks, BlockIndex, Arcs, ArcCounts, Summary
600}